OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "config.h" | |
6 | |
7 #include "CCLayerTreeHostImpl.h" | |
8 | |
9 #include "CCAnimationTestCommon.h" | |
10 #include "CCDelegatedRendererLayerImpl.h" | |
11 #include "CCGeometryTestUtils.h" | |
12 #include "CCHeadsUpDisplayLayerImpl.h" | |
13 #include "CCIOSurfaceLayerImpl.h" | |
14 #include "CCLayerImpl.h" | |
15 #include "CCLayerTestCommon.h" | |
16 #include "CCLayerTilingData.h" | |
17 #include "CCQuadSink.h" | |
18 #include "CCRenderPassDrawQuad.h" | |
19 #include "CCRenderPassTestCommon.h" | |
20 #include "CCRendererGL.h" | |
21 #include "CCScrollbarGeometryFixedThumb.h" | |
22 #include "CCScrollbarLayerImpl.h" | |
23 #include "CCSettings.h" | |
24 #include "CCSingleThreadProxy.h" | |
25 #include "CCSolidColorDrawQuad.h" | |
26 #include "CCTestCommon.h" | |
27 #include "CCTextureDrawQuad.h" | |
28 #include "CCTextureLayerImpl.h" | |
29 #include "CCTileDrawQuad.h" | |
30 #include "CCTiledLayerImpl.h" | |
31 #include "CCVideoLayerImpl.h" | |
32 #include "FakeWebCompositorOutputSurface.h" | |
33 #include "FakeWebGraphicsContext3D.h" | |
34 #include "FakeWebScrollbarThemeGeometry.h" | |
35 #include "base/hash_tables.h" | |
36 #include "testing/gmock/include/gmock/gmock.h" | |
37 #include "testing/gtest/include/gtest/gtest.h" | |
38 #include <public/WebVideoFrame.h> | |
39 #include <public/WebVideoFrameProvider.h> | |
40 | |
41 using namespace cc; | |
42 using namespace CCLayerTestCommon; | |
43 using namespace WebKit; | |
44 using namespace WebKitTests; | |
45 | |
46 using ::testing::Mock; | |
47 using ::testing::Return; | |
48 using ::testing::AnyNumber; | |
49 using ::testing::AtLeast; | |
50 using ::testing::_; | |
51 | |
52 namespace { | |
53 | |
54 // This test is parametrized to run all tests with the | |
55 // CCSettings::pageScalePinchZoomEnabled field enabled and disabled. | |
56 class CCLayerTreeHostImplTest : public testing::TestWithParam<bool>, | |
57 public CCLayerTreeHostImplClient { | |
58 public: | |
59 CCLayerTreeHostImplTest() | |
60 : m_onCanDrawStateChangedCalled(false) | |
61 , m_didRequestCommit(false) | |
62 , m_didRequestRedraw(false) | |
63 { | |
64 } | |
65 | |
66 virtual void SetUp() | |
67 { | |
68 CCSettings::setPageScalePinchZoomEnabled(GetParam()); | |
69 CCLayerTreeSettings settings; | |
70 settings.minimumOcclusionTrackingSize = IntSize(); | |
71 | |
72 m_hostImpl = CCLayerTreeHostImpl::create(settings, this); | |
73 m_hostImpl->initializeRenderer(createContext()); | |
74 m_hostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10)); | |
75 } | |
76 | |
77 virtual void TearDown() | |
78 { | |
79 CCSettings::reset(); | |
80 } | |
81 | |
82 virtual void didLoseContextOnImplThread() OVERRIDE { } | |
83 virtual void onSwapBuffersCompleteOnImplThread() OVERRIDE { } | |
84 virtual void onVSyncParametersChanged(double, double) OVERRIDE { } | |
85 virtual void onCanDrawStateChanged(bool canDraw) OVERRIDE { m_onCanDrawState
ChangedCalled = true; } | |
86 virtual void setNeedsRedrawOnImplThread() OVERRIDE { m_didRequestRedraw = tr
ue; } | |
87 virtual void setNeedsCommitOnImplThread() OVERRIDE { m_didRequestCommit = tr
ue; } | |
88 virtual void postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAnimat
ionEventsVector>, double wallClockTime) OVERRIDE { } | |
89 virtual void releaseContentsTexturesOnImplThread() OVERRIDE { } | |
90 | |
91 scoped_ptr<CCLayerTreeHostImpl> createLayerTreeHost(bool partialSwap, scoped
_ptr<CCGraphicsContext> graphicsContext, scoped_ptr<CCLayerImpl> root) | |
92 { | |
93 CCSettings::setPartialSwapEnabled(partialSwap); | |
94 | |
95 CCLayerTreeSettings settings; | |
96 settings.minimumOcclusionTrackingSize = IntSize(); | |
97 | |
98 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create
(settings, this); | |
99 | |
100 myHostImpl->initializeRenderer(graphicsContext.Pass()); | |
101 myHostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10)); | |
102 | |
103 root->setAnchorPoint(FloatPoint(0, 0)); | |
104 root->setPosition(FloatPoint(0, 0)); | |
105 root->setBounds(IntSize(10, 10)); | |
106 root->setContentBounds(IntSize(10, 10)); | |
107 root->setVisibleContentRect(IntRect(0, 0, 10, 10)); | |
108 root->setDrawsContent(true); | |
109 myHostImpl->setRootLayer(root.Pass()); | |
110 return myHostImpl.Pass(); | |
111 } | |
112 | |
113 static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer) | |
114 { | |
115 ASSERT_EQ(layer->scrollDelta(), IntSize()); | |
116 for (size_t i = 0; i < layer->children().size(); ++i) | |
117 expectClearedScrollDeltasRecursive(layer->children()[i]); | |
118 } | |
119 | |
120 static void expectContains(const CCScrollAndScaleSet& scrollInfo, int id, co
nst IntSize& scrollDelta) | |
121 { | |
122 int timesEncountered = 0; | |
123 | |
124 for (size_t i = 0; i < scrollInfo.scrolls.size(); ++i) { | |
125 if (scrollInfo.scrolls[i].layerId != id) | |
126 continue; | |
127 EXPECT_EQ(scrollDelta.width(), scrollInfo.scrolls[i].scrollDelta.wid
th()); | |
128 EXPECT_EQ(scrollDelta.height(), scrollInfo.scrolls[i].scrollDelta.he
ight()); | |
129 timesEncountered++; | |
130 } | |
131 | |
132 ASSERT_EQ(timesEncountered, 1); | |
133 } | |
134 | |
135 void setupScrollAndContentsLayers(const IntSize& contentSize) | |
136 { | |
137 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
138 root->setScrollable(true); | |
139 root->setScrollPosition(IntPoint(0, 0)); | |
140 root->setMaxScrollPosition(contentSize); | |
141 root->setBounds(contentSize); | |
142 root->setContentBounds(contentSize); | |
143 root->setPosition(FloatPoint(0, 0)); | |
144 root->setAnchorPoint(FloatPoint(0, 0)); | |
145 | |
146 scoped_ptr<CCLayerImpl> contents = CCLayerImpl::create(2); | |
147 contents->setDrawsContent(true); | |
148 contents->setBounds(contentSize); | |
149 contents->setContentBounds(contentSize); | |
150 contents->setPosition(FloatPoint(0, 0)); | |
151 contents->setAnchorPoint(FloatPoint(0, 0)); | |
152 root->addChild(contents.Pass()); | |
153 m_hostImpl->setRootLayer(root.Pass()); | |
154 } | |
155 | |
156 static scoped_ptr<CCLayerImpl> createScrollableLayer(int id, const IntSize&
size) | |
157 { | |
158 scoped_ptr<CCLayerImpl> layer = CCLayerImpl::create(id); | |
159 layer->setScrollable(true); | |
160 layer->setDrawsContent(true); | |
161 layer->setBounds(size); | |
162 layer->setContentBounds(size); | |
163 layer->setMaxScrollPosition(IntSize(size.width() * 2, size.height() * 2)
); | |
164 return layer.Pass(); | |
165 } | |
166 | |
167 void initializeRendererAndDrawFrame() | |
168 { | |
169 m_hostImpl->initializeRenderer(createContext()); | |
170 CCLayerTreeHostImpl::FrameData frame; | |
171 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
172 m_hostImpl->drawLayers(frame); | |
173 m_hostImpl->didDrawAllLayers(frame); | |
174 } | |
175 | |
176 protected: | |
177 scoped_ptr<CCGraphicsContext> createContext() | |
178 { | |
179 return FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphi
csContext3D)).PassAs<CCGraphicsContext>(); | |
180 } | |
181 | |
182 DebugScopedSetImplThread m_alwaysImplThread; | |
183 DebugScopedSetMainThreadBlocked m_alwaysMainThreadBlocked; | |
184 | |
185 scoped_ptr<CCLayerTreeHostImpl> m_hostImpl; | |
186 bool m_onCanDrawStateChangedCalled; | |
187 bool m_didRequestCommit; | |
188 bool m_didRequestRedraw; | |
189 CCScopedSettings m_scopedSettings; | |
190 }; | |
191 | |
192 class FakeWebGraphicsContext3DMakeCurrentFails : public FakeWebGraphicsContext3D
{ | |
193 public: | |
194 virtual bool makeContextCurrent() { return false; } | |
195 }; | |
196 | |
197 TEST_P(CCLayerTreeHostImplTest, notifyIfCanDrawChanged) | |
198 { | |
199 // Note: It is not possible to disable the renderer once it has been set, | |
200 // so we do not need to test that disabling the renderer notifies us | |
201 // that canDraw changed. | |
202 EXPECT_FALSE(m_hostImpl->canDraw()); | |
203 m_onCanDrawStateChangedCalled = false; | |
204 | |
205 setupScrollAndContentsLayers(IntSize(100, 100)); | |
206 EXPECT_TRUE(m_hostImpl->canDraw()); | |
207 EXPECT_TRUE(m_onCanDrawStateChangedCalled); | |
208 m_onCanDrawStateChangedCalled = false; | |
209 | |
210 // Toggle the root layer to make sure it toggles canDraw | |
211 m_hostImpl->setRootLayer(scoped_ptr<CCLayerImpl>()); | |
212 EXPECT_FALSE(m_hostImpl->canDraw()); | |
213 EXPECT_TRUE(m_onCanDrawStateChangedCalled); | |
214 m_onCanDrawStateChangedCalled = false; | |
215 | |
216 setupScrollAndContentsLayers(IntSize(100, 100)); | |
217 EXPECT_TRUE(m_hostImpl->canDraw()); | |
218 EXPECT_TRUE(m_onCanDrawStateChangedCalled); | |
219 m_onCanDrawStateChangedCalled = false; | |
220 | |
221 // Toggle the device viewport size to make sure it toggles canDraw. | |
222 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(0, 0)); | |
223 EXPECT_FALSE(m_hostImpl->canDraw()); | |
224 EXPECT_TRUE(m_onCanDrawStateChangedCalled); | |
225 m_onCanDrawStateChangedCalled = false; | |
226 | |
227 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100)); | |
228 EXPECT_TRUE(m_hostImpl->canDraw()); | |
229 EXPECT_TRUE(m_onCanDrawStateChangedCalled); | |
230 m_onCanDrawStateChangedCalled = false; | |
231 | |
232 // Toggle contents textures purged to make sure it toggles canDraw | |
233 m_hostImpl->releaseContentsTextures(); | |
234 EXPECT_FALSE(m_hostImpl->canDraw()); | |
235 EXPECT_TRUE(m_onCanDrawStateChangedCalled); | |
236 m_onCanDrawStateChangedCalled = false; | |
237 | |
238 m_hostImpl->resetContentsTexturesPurged(); | |
239 EXPECT_TRUE(m_hostImpl->canDraw()); | |
240 EXPECT_TRUE(m_onCanDrawStateChangedCalled); | |
241 m_onCanDrawStateChangedCalled = false; | |
242 } | |
243 | |
244 TEST_P(CCLayerTreeHostImplTest, scrollDeltaNoLayers) | |
245 { | |
246 ASSERT_FALSE(m_hostImpl->rootLayer()); | |
247 | |
248 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas
(); | |
249 ASSERT_EQ(scrollInfo->scrolls.size(), 0u); | |
250 } | |
251 | |
252 TEST_P(CCLayerTreeHostImplTest, scrollDeltaTreeButNoChanges) | |
253 { | |
254 { | |
255 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
256 root->addChild(CCLayerImpl::create(2)); | |
257 root->addChild(CCLayerImpl::create(3)); | |
258 root->children()[1]->addChild(CCLayerImpl::create(4)); | |
259 root->children()[1]->addChild(CCLayerImpl::create(5)); | |
260 root->children()[1]->children()[0]->addChild(CCLayerImpl::create(6)); | |
261 m_hostImpl->setRootLayer(root.Pass()); | |
262 } | |
263 CCLayerImpl* root = m_hostImpl->rootLayer(); | |
264 | |
265 expectClearedScrollDeltasRecursive(root); | |
266 | |
267 scoped_ptr<CCScrollAndScaleSet> scrollInfo; | |
268 | |
269 scrollInfo = m_hostImpl->processScrollDeltas(); | |
270 ASSERT_EQ(scrollInfo->scrolls.size(), 0u); | |
271 expectClearedScrollDeltasRecursive(root); | |
272 | |
273 scrollInfo = m_hostImpl->processScrollDeltas(); | |
274 ASSERT_EQ(scrollInfo->scrolls.size(), 0u); | |
275 expectClearedScrollDeltasRecursive(root); | |
276 } | |
277 | |
278 TEST_P(CCLayerTreeHostImplTest, scrollDeltaRepeatedScrolls) | |
279 { | |
280 IntPoint scrollPosition(20, 30); | |
281 IntSize scrollDelta(11, -15); | |
282 { | |
283 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
284 root->setScrollPosition(scrollPosition); | |
285 root->setScrollable(true); | |
286 root->setMaxScrollPosition(IntSize(100, 100)); | |
287 root->scrollBy(scrollDelta); | |
288 m_hostImpl->setRootLayer(root.Pass()); | |
289 } | |
290 CCLayerImpl* root = m_hostImpl->rootLayer(); | |
291 | |
292 scoped_ptr<CCScrollAndScaleSet> scrollInfo; | |
293 | |
294 scrollInfo = m_hostImpl->processScrollDeltas(); | |
295 ASSERT_EQ(scrollInfo->scrolls.size(), 1u); | |
296 EXPECT_EQ(root->sentScrollDelta(), scrollDelta); | |
297 expectContains(*scrollInfo, root->id(), scrollDelta); | |
298 | |
299 IntSize scrollDelta2(-5, 27); | |
300 root->scrollBy(scrollDelta2); | |
301 scrollInfo = m_hostImpl->processScrollDeltas(); | |
302 ASSERT_EQ(scrollInfo->scrolls.size(), 1u); | |
303 EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2); | |
304 expectContains(*scrollInfo, root->id(), scrollDelta + scrollDelta2); | |
305 | |
306 root->scrollBy(IntSize()); | |
307 scrollInfo = m_hostImpl->processScrollDeltas(); | |
308 EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2); | |
309 } | |
310 | |
311 TEST_P(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw) | |
312 { | |
313 setupScrollAndContentsLayers(IntSize(100, 100)); | |
314 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
315 initializeRendererAndDrawFrame(); | |
316 | |
317 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
318 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); | |
319 m_hostImpl->scrollEnd(); | |
320 EXPECT_TRUE(m_didRequestRedraw); | |
321 EXPECT_TRUE(m_didRequestCommit); | |
322 } | |
323 | |
324 TEST_P(CCLayerTreeHostImplTest, scrollWithoutRootLayer) | |
325 { | |
326 // We should not crash when trying to scroll an empty layer tree. | |
327 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollIgnored); | |
328 } | |
329 | |
330 TEST_P(CCLayerTreeHostImplTest, scrollWithoutRenderer) | |
331 { | |
332 CCLayerTreeSettings settings; | |
333 m_hostImpl = CCLayerTreeHostImpl::create(settings, this); | |
334 | |
335 // Initialization will fail here. | |
336 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptP
tr(new FakeWebGraphicsContext3DMakeCurrentFails)).PassAs<CCGraphicsContext>()); | |
337 m_hostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10)); | |
338 | |
339 setupScrollAndContentsLayers(IntSize(100, 100)); | |
340 | |
341 // We should not crash when trying to scroll after the renderer initializati
on fails. | |
342 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollIgnored); | |
343 } | |
344 | |
345 TEST_P(CCLayerTreeHostImplTest, replaceTreeWhileScrolling) | |
346 { | |
347 const int scrollLayerId = 1; | |
348 | |
349 setupScrollAndContentsLayers(IntSize(100, 100)); | |
350 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
351 initializeRendererAndDrawFrame(); | |
352 | |
353 // We should not crash if the tree is replaced while we are scrolling. | |
354 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
355 m_hostImpl->detachLayerTree(); | |
356 | |
357 setupScrollAndContentsLayers(IntSize(100, 100)); | |
358 | |
359 // We should still be scrolling, because the scrolled layer also exists in t
he new tree. | |
360 IntSize scrollDelta(0, 10); | |
361 m_hostImpl->scrollBy(IntPoint(), scrollDelta); | |
362 m_hostImpl->scrollEnd(); | |
363 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas
(); | |
364 expectContains(*scrollInfo, scrollLayerId, scrollDelta); | |
365 } | |
366 | |
367 TEST_P(CCLayerTreeHostImplTest, clearRootRenderSurfaceAndScroll) | |
368 { | |
369 setupScrollAndContentsLayers(IntSize(100, 100)); | |
370 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
371 initializeRendererAndDrawFrame(); | |
372 | |
373 // We should be able to scroll even if the root layer loses its render surfa
ce after the most | |
374 // recent render. | |
375 m_hostImpl->rootLayer()->clearRenderSurface(); | |
376 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
377 } | |
378 | |
379 TEST_P(CCLayerTreeHostImplTest, wheelEventHandlers) | |
380 { | |
381 setupScrollAndContentsLayers(IntSize(100, 100)); | |
382 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
383 initializeRendererAndDrawFrame(); | |
384 CCLayerImpl* root = m_hostImpl->rootLayer(); | |
385 | |
386 root->setHaveWheelEventHandlers(true); | |
387 | |
388 // With registered event handlers, wheel scrolls have to go to the main thre
ad. | |
389 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollOnMainThread); | |
390 | |
391 // But gesture scrolls can still be handled. | |
392 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gest
ure), CCInputHandlerClient::ScrollStarted); | |
393 } | |
394 | |
395 TEST_P(CCLayerTreeHostImplTest, shouldScrollOnMainThread) | |
396 { | |
397 setupScrollAndContentsLayers(IntSize(100, 100)); | |
398 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
399 initializeRendererAndDrawFrame(); | |
400 CCLayerImpl* root = m_hostImpl->rootLayer(); | |
401 | |
402 root->setShouldScrollOnMainThread(true); | |
403 | |
404 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollOnMainThread); | |
405 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gest
ure), CCInputHandlerClient::ScrollOnMainThread); | |
406 } | |
407 | |
408 TEST_P(CCLayerTreeHostImplTest, nonFastScrollableRegionBasic) | |
409 { | |
410 setupScrollAndContentsLayers(IntSize(200, 200)); | |
411 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100)); | |
412 initializeRendererAndDrawFrame(); | |
413 CCLayerImpl* root = m_hostImpl->rootLayer(); | |
414 | |
415 root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50)); | |
416 | |
417 // All scroll types inside the non-fast scrollable region should fail. | |
418 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wh
eel), CCInputHandlerClient::ScrollOnMainThread); | |
419 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Ge
sture), CCInputHandlerClient::ScrollOnMainThread); | |
420 | |
421 // All scroll types outside this region should succeed. | |
422 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Wh
eel), CCInputHandlerClient::ScrollStarted); | |
423 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); | |
424 m_hostImpl->scrollEnd(); | |
425 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Ge
sture), CCInputHandlerClient::ScrollStarted); | |
426 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); | |
427 m_hostImpl->scrollEnd(); | |
428 } | |
429 | |
430 TEST_P(CCLayerTreeHostImplTest, nonFastScrollableRegionWithOffset) | |
431 { | |
432 setupScrollAndContentsLayers(IntSize(200, 200)); | |
433 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100)); | |
434 CCLayerImpl* root = m_hostImpl->rootLayer(); | |
435 | |
436 root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50)); | |
437 root->setPosition(FloatPoint(-25, 0)); | |
438 initializeRendererAndDrawFrame(); | |
439 | |
440 // This point would fall into the non-fast scrollable region except that we'
ve moved the layer down by 25 pixels. | |
441 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(40, 10), CCInputHandlerClient::Wh
eel), CCInputHandlerClient::ScrollStarted); | |
442 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 1)); | |
443 m_hostImpl->scrollEnd(); | |
444 | |
445 // This point is still inside the non-fast region. | |
446 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(10, 10), CCInputHandlerClient::Wh
eel), CCInputHandlerClient::ScrollOnMainThread); | |
447 } | |
448 | |
449 TEST_P(CCLayerTreeHostImplTest, maxScrollPositionChangedByDeviceScaleFactor) | |
450 { | |
451 setupScrollAndContentsLayers(IntSize(100, 100)); | |
452 | |
453 float deviceScaleFactor = 2; | |
454 IntSize layoutViewport(25, 25); | |
455 IntSize deviceViewport(layoutViewport); | |
456 deviceViewport.scale(deviceScaleFactor); | |
457 m_hostImpl->setViewportSize(layoutViewport, deviceViewport); | |
458 m_hostImpl->setDeviceScaleFactor(deviceScaleFactor); | |
459 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(25, 25)); | |
460 | |
461 deviceScaleFactor = 1; | |
462 m_hostImpl->setViewportSize(layoutViewport, layoutViewport); | |
463 m_hostImpl->setDeviceScaleFactor(deviceScaleFactor); | |
464 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(75, 75)); | |
465 } | |
466 | |
467 TEST_P(CCLayerTreeHostImplTest, implPinchZoom) | |
468 { | |
469 // This test is specific to the page-scale based pinch zoom. | |
470 if (!CCSettings::pageScalePinchZoomEnabled()) | |
471 return; | |
472 | |
473 setupScrollAndContentsLayers(IntSize(100, 100)); | |
474 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
475 initializeRendererAndDrawFrame(); | |
476 | |
477 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); | |
478 ASSERT(scrollLayer); | |
479 | |
480 const float minPageScale = 1, maxPageScale = 4; | |
481 const WebTransformationMatrix identityScaleTransform; | |
482 | |
483 // The impl-based pinch zoome should not adjust the max scroll position. | |
484 { | |
485 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
486 scrollLayer->setImplTransform(identityScaleTransform); | |
487 scrollLayer->setScrollDelta(IntSize()); | |
488 | |
489 float pageScaleDelta = 2; | |
490 m_hostImpl->pinchGestureBegin(); | |
491 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50)); | |
492 m_hostImpl->pinchGestureEnd(); | |
493 EXPECT_TRUE(m_didRequestRedraw); | |
494 EXPECT_TRUE(m_didRequestCommit); | |
495 | |
496 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
497 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); | |
498 | |
499 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(50, 50))
; | |
500 } | |
501 | |
502 // Scrolling after a pinch gesture should always be in local space. The scr
oll deltas do not | |
503 // have the page scale factor applied. | |
504 { | |
505 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
506 scrollLayer->setImplTransform(identityScaleTransform); | |
507 scrollLayer->setScrollDelta(IntSize()); | |
508 | |
509 float pageScaleDelta = 2; | |
510 m_hostImpl->pinchGestureBegin(); | |
511 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0)); | |
512 m_hostImpl->pinchGestureEnd(); | |
513 | |
514 IntSize scrollDelta(0, 10); | |
515 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::
Wheel), CCInputHandlerClient::ScrollStarted); | |
516 m_hostImpl->scrollBy(IntPoint(), scrollDelta); | |
517 m_hostImpl->scrollEnd(); | |
518 | |
519 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
520 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), scrollD
elta); | |
521 } | |
522 } | |
523 | |
524 TEST_P(CCLayerTreeHostImplTest, pinchGesture) | |
525 { | |
526 setupScrollAndContentsLayers(IntSize(100, 100)); | |
527 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
528 initializeRendererAndDrawFrame(); | |
529 | |
530 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); | |
531 ASSERT(scrollLayer); | |
532 | |
533 const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5
; | |
534 const float maxPageScale = 4; | |
535 const WebTransformationMatrix identityScaleTransform; | |
536 | |
537 // Basic pinch zoom in gesture | |
538 { | |
539 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
540 scrollLayer->setImplTransform(identityScaleTransform); | |
541 scrollLayer->setScrollDelta(IntSize()); | |
542 | |
543 float pageScaleDelta = 2; | |
544 m_hostImpl->pinchGestureBegin(); | |
545 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50)); | |
546 m_hostImpl->pinchGestureEnd(); | |
547 EXPECT_TRUE(m_didRequestRedraw); | |
548 EXPECT_TRUE(m_didRequestCommit); | |
549 | |
550 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
551 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); | |
552 } | |
553 | |
554 // Zoom-in clamping | |
555 { | |
556 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
557 scrollLayer->setImplTransform(identityScaleTransform); | |
558 scrollLayer->setScrollDelta(IntSize()); | |
559 float pageScaleDelta = 10; | |
560 | |
561 m_hostImpl->pinchGestureBegin(); | |
562 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50)); | |
563 m_hostImpl->pinchGestureEnd(); | |
564 | |
565 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
566 EXPECT_EQ(scrollInfo->pageScaleDelta, maxPageScale); | |
567 } | |
568 | |
569 // Zoom-out clamping | |
570 { | |
571 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
572 scrollLayer->setImplTransform(identityScaleTransform); | |
573 scrollLayer->setScrollDelta(IntSize()); | |
574 scrollLayer->setScrollPosition(IntPoint(50, 50)); | |
575 | |
576 float pageScaleDelta = 0.1f; | |
577 m_hostImpl->pinchGestureBegin(); | |
578 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0)); | |
579 m_hostImpl->pinchGestureEnd(); | |
580 | |
581 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
582 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); | |
583 | |
584 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
585 // Pushed to (0,0) via clamping against contents layer size. | |
586 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50)); | |
587 } else { | |
588 EXPECT_TRUE(scrollInfo->scrolls.isEmpty()); | |
589 } | |
590 } | |
591 | |
592 // Two-finger panning | |
593 { | |
594 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
595 scrollLayer->setImplTransform(identityScaleTransform); | |
596 scrollLayer->setScrollDelta(IntSize()); | |
597 scrollLayer->setScrollPosition(IntPoint(20, 20)); | |
598 | |
599 float pageScaleDelta = 1; | |
600 m_hostImpl->pinchGestureBegin(); | |
601 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(10, 10)); | |
602 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(20, 20)); | |
603 m_hostImpl->pinchGestureEnd(); | |
604 | |
605 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
606 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); | |
607 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-10, -10)); | |
608 } | |
609 } | |
610 | |
611 TEST_P(CCLayerTreeHostImplTest, pageScaleAnimation) | |
612 { | |
613 setupScrollAndContentsLayers(IntSize(100, 100)); | |
614 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
615 initializeRendererAndDrawFrame(); | |
616 | |
617 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); | |
618 ASSERT(scrollLayer); | |
619 | |
620 const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5
; | |
621 const float maxPageScale = 4; | |
622 const double startTime = 1; | |
623 const double duration = 0.1; | |
624 const double halfwayThroughAnimation = startTime + duration / 2; | |
625 const double endTime = startTime + duration; | |
626 const WebTransformationMatrix identityScaleTransform; | |
627 | |
628 // Non-anchor zoom-in | |
629 { | |
630 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
631 scrollLayer->setImplTransform(identityScaleTransform); | |
632 scrollLayer->setScrollPosition(IntPoint(50, 50)); | |
633 | |
634 m_hostImpl->startPageScaleAnimation(IntSize(0, 0), false, 2, startTime,
duration); | |
635 m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation); | |
636 EXPECT_TRUE(m_didRequestRedraw); | |
637 m_hostImpl->animate(endTime, endTime); | |
638 EXPECT_TRUE(m_didRequestCommit); | |
639 | |
640 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
641 EXPECT_EQ(scrollInfo->pageScaleDelta, 2); | |
642 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50)); | |
643 } | |
644 | |
645 // Anchor zoom-out | |
646 { | |
647 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
648 scrollLayer->setImplTransform(identityScaleTransform); | |
649 scrollLayer->setScrollPosition(IntPoint(50, 50)); | |
650 | |
651 m_hostImpl->startPageScaleAnimation(IntSize(25, 25), true, minPageScale,
startTime, duration); | |
652 m_hostImpl->animate(endTime, endTime); | |
653 EXPECT_TRUE(m_didRequestRedraw); | |
654 EXPECT_TRUE(m_didRequestCommit); | |
655 | |
656 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
657 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); | |
658 // Pushed to (0,0) via clamping against contents layer size. | |
659 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50)); | |
660 } | |
661 } | |
662 | |
663 TEST_P(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhilePinchZoomin
g) | |
664 { | |
665 setupScrollAndContentsLayers(IntSize(100, 100)); | |
666 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
667 initializeRendererAndDrawFrame(); | |
668 | |
669 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); | |
670 ASSERT(scrollLayer); | |
671 | |
672 const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5
; | |
673 const float maxPageScale = 4; | |
674 | |
675 // Pinch zoom in. | |
676 { | |
677 // Start a pinch in gesture at the bottom right corner of the viewport. | |
678 const float zoomInDelta = 2; | |
679 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
680 m_hostImpl->pinchGestureBegin(); | |
681 m_hostImpl->pinchGestureUpdate(zoomInDelta, IntPoint(50, 50)); | |
682 | |
683 // Because we are pinch zooming in, we shouldn't get any scroll or page | |
684 // scale deltas. | |
685 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
686 EXPECT_EQ(scrollInfo->pageScaleDelta, 1); | |
687 EXPECT_EQ(scrollInfo->scrolls.size(), 0u); | |
688 | |
689 // Once the gesture ends, we get the final scroll and page scale values. | |
690 m_hostImpl->pinchGestureEnd(); | |
691 scrollInfo = m_hostImpl->processScrollDeltas(); | |
692 EXPECT_EQ(scrollInfo->pageScaleDelta, zoomInDelta); | |
693 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
694 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25)); | |
695 } else { | |
696 EXPECT_TRUE(scrollInfo->scrolls.isEmpty()); | |
697 } | |
698 } | |
699 | |
700 // Pinch zoom out. | |
701 { | |
702 // Start a pinch out gesture at the bottom right corner of the viewport. | |
703 const float zoomOutDelta = 0.75; | |
704 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
705 m_hostImpl->pinchGestureBegin(); | |
706 m_hostImpl->pinchGestureUpdate(zoomOutDelta, IntPoint(50, 50)); | |
707 | |
708 // Since we are pinch zooming out, we should get an update to zoom all | |
709 // the way out to the minimum page scale. | |
710 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
711 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
712 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); | |
713 expectContains(*scrollInfo, scrollLayer->id(), IntSize(0, 0)); | |
714 } else { | |
715 EXPECT_EQ(scrollInfo->pageScaleDelta, 1); | |
716 EXPECT_TRUE(scrollInfo->scrolls.isEmpty()); | |
717 } | |
718 | |
719 // Once the gesture ends, we get the final scroll and page scale values. | |
720 m_hostImpl->pinchGestureEnd(); | |
721 scrollInfo = m_hostImpl->processScrollDeltas(); | |
722 if (CCSettings::pageScalePinchZoomEnabled()) { | |
723 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale); | |
724 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25)); | |
725 } else { | |
726 EXPECT_EQ(scrollInfo->pageScaleDelta, zoomOutDelta); | |
727 expectContains(*scrollInfo, scrollLayer->id(), IntSize(8, 8)); | |
728 } | |
729 } | |
730 } | |
731 | |
732 TEST_P(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhileAnimatingPa
geScale) | |
733 { | |
734 setupScrollAndContentsLayers(IntSize(100, 100)); | |
735 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50)); | |
736 initializeRendererAndDrawFrame(); | |
737 | |
738 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer(); | |
739 ASSERT(scrollLayer); | |
740 | |
741 const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5
; | |
742 const float maxPageScale = 4; | |
743 const double startTime = 1; | |
744 const double duration = 0.1; | |
745 const double halfwayThroughAnimation = startTime + duration / 2; | |
746 const double endTime = startTime + duration; | |
747 | |
748 // Start a page scale animation. | |
749 const float pageScaleDelta = 2; | |
750 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale); | |
751 m_hostImpl->startPageScaleAnimation(IntSize(50, 50), false, pageScaleDelta,
startTime, duration); | |
752 | |
753 // We should immediately get the final zoom and scroll values for the | |
754 // animation. | |
755 m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation); | |
756 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas
(); | |
757 | |
758 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
759 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); | |
760 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25)); | |
761 } else { | |
762 EXPECT_EQ(scrollInfo->pageScaleDelta, 1); | |
763 EXPECT_TRUE(scrollInfo->scrolls.isEmpty()); | |
764 } | |
765 | |
766 // Scrolling during the animation is ignored. | |
767 const IntSize scrollDelta(0, 10); | |
768 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wh
eel), CCInputHandlerClient::ScrollStarted); | |
769 m_hostImpl->scrollBy(IntPoint(), scrollDelta); | |
770 m_hostImpl->scrollEnd(); | |
771 | |
772 // The final page scale and scroll deltas should match what we got | |
773 // earlier. | |
774 m_hostImpl->animate(endTime, endTime); | |
775 scrollInfo = m_hostImpl->processScrollDeltas(); | |
776 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta); | |
777 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25)); | |
778 } | |
779 | |
780 class DidDrawCheckLayer : public CCTiledLayerImpl { | |
781 public: | |
782 static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImp
l>(new DidDrawCheckLayer(id)); } | |
783 | |
784 virtual void didDraw(CCResourceProvider*) OVERRIDE | |
785 { | |
786 m_didDrawCalled = true; | |
787 } | |
788 | |
789 virtual void willDraw(CCResourceProvider*) OVERRIDE | |
790 { | |
791 m_willDrawCalled = true; | |
792 } | |
793 | |
794 bool didDrawCalled() const { return m_didDrawCalled; } | |
795 bool willDrawCalled() const { return m_willDrawCalled; } | |
796 | |
797 void clearDidDrawCheck() | |
798 { | |
799 m_didDrawCalled = false; | |
800 m_willDrawCalled = false; | |
801 } | |
802 | |
803 protected: | |
804 explicit DidDrawCheckLayer(int id) | |
805 : CCTiledLayerImpl(id) | |
806 , m_didDrawCalled(false) | |
807 , m_willDrawCalled(false) | |
808 { | |
809 setAnchorPoint(FloatPoint(0, 0)); | |
810 setBounds(IntSize(10, 10)); | |
811 setContentBounds(IntSize(10, 10)); | |
812 setDrawsContent(true); | |
813 setSkipsDraw(false); | |
814 setVisibleContentRect(IntRect(0, 0, 10, 10)); | |
815 | |
816 OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(100,
100), CCLayerTilingData::HasBorderTexels); | |
817 tiler->setBounds(contentBounds()); | |
818 setTilingData(*tiler.get()); | |
819 } | |
820 | |
821 private: | |
822 bool m_didDrawCalled; | |
823 bool m_willDrawCalled; | |
824 }; | |
825 | |
826 TEST_P(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer) | |
827 { | |
828 // The root layer is always drawn, so run this test on a child layer that | |
829 // will be masked out by the root layer's bounds. | |
830 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); | |
831 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLa
yer()); | |
832 root->setMasksToBounds(true); | |
833 | |
834 root->addChild(DidDrawCheckLayer::create(2)); | |
835 DidDrawCheckLayer* layer = static_cast<DidDrawCheckLayer*>(root->children()[
0]); | |
836 // Ensure visibleContentRect for layer is empty | |
837 layer->setPosition(FloatPoint(100, 100)); | |
838 layer->setBounds(IntSize(10, 10)); | |
839 layer->setContentBounds(IntSize(10, 10)); | |
840 | |
841 CCLayerTreeHostImpl::FrameData frame; | |
842 | |
843 EXPECT_FALSE(layer->willDrawCalled()); | |
844 EXPECT_FALSE(layer->didDrawCalled()); | |
845 | |
846 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
847 m_hostImpl->drawLayers(frame); | |
848 m_hostImpl->didDrawAllLayers(frame); | |
849 | |
850 EXPECT_FALSE(layer->willDrawCalled()); | |
851 EXPECT_FALSE(layer->didDrawCalled()); | |
852 | |
853 EXPECT_TRUE(layer->visibleContentRect().isEmpty()); | |
854 | |
855 // Ensure visibleContentRect for layer layer is not empty | |
856 layer->setPosition(FloatPoint(0, 0)); | |
857 | |
858 EXPECT_FALSE(layer->willDrawCalled()); | |
859 EXPECT_FALSE(layer->didDrawCalled()); | |
860 | |
861 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
862 m_hostImpl->drawLayers(frame); | |
863 m_hostImpl->didDrawAllLayers(frame); | |
864 | |
865 EXPECT_TRUE(layer->willDrawCalled()); | |
866 EXPECT_TRUE(layer->didDrawCalled()); | |
867 | |
868 EXPECT_FALSE(layer->visibleContentRect().isEmpty()); | |
869 } | |
870 | |
871 TEST_P(CCLayerTreeHostImplTest, willDrawNotCalledOnOccludedLayer) | |
872 { | |
873 IntSize bigSize(1000, 1000); | |
874 m_hostImpl->setViewportSize(bigSize, bigSize); | |
875 | |
876 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); | |
877 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLa
yer()); | |
878 | |
879 root->addChild(DidDrawCheckLayer::create(2)); | |
880 DidDrawCheckLayer* occludedLayer = static_cast<DidDrawCheckLayer*>(root->chi
ldren()[0]); | |
881 | |
882 root->addChild(DidDrawCheckLayer::create(3)); | |
883 DidDrawCheckLayer* topLayer = static_cast<DidDrawCheckLayer*>(root->children
()[1]); | |
884 // This layer covers the occludedLayer above. Make this layer large so it ca
n occlude. | |
885 topLayer->setBounds(bigSize); | |
886 topLayer->setContentBounds(bigSize); | |
887 topLayer->setContentsOpaque(true); | |
888 | |
889 CCLayerTreeHostImpl::FrameData frame; | |
890 | |
891 EXPECT_FALSE(occludedLayer->willDrawCalled()); | |
892 EXPECT_FALSE(occludedLayer->didDrawCalled()); | |
893 EXPECT_FALSE(topLayer->willDrawCalled()); | |
894 EXPECT_FALSE(topLayer->didDrawCalled()); | |
895 | |
896 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
897 m_hostImpl->drawLayers(frame); | |
898 m_hostImpl->didDrawAllLayers(frame); | |
899 | |
900 EXPECT_FALSE(occludedLayer->willDrawCalled()); | |
901 EXPECT_FALSE(occludedLayer->didDrawCalled()); | |
902 EXPECT_TRUE(topLayer->willDrawCalled()); | |
903 EXPECT_TRUE(topLayer->didDrawCalled()); | |
904 } | |
905 | |
906 TEST_P(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers) | |
907 { | |
908 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); | |
909 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLa
yer()); | |
910 | |
911 root->addChild(DidDrawCheckLayer::create(2)); | |
912 DidDrawCheckLayer* layer1 = static_cast<DidDrawCheckLayer*>(root->children()
[0]); | |
913 | |
914 layer1->addChild(DidDrawCheckLayer::create(3)); | |
915 DidDrawCheckLayer* layer2 = static_cast<DidDrawCheckLayer*>(layer1->children
()[0]); | |
916 | |
917 layer1->setOpacity(0.3f); | |
918 layer1->setPreserves3D(false); | |
919 | |
920 EXPECT_FALSE(root->didDrawCalled()); | |
921 EXPECT_FALSE(layer1->didDrawCalled()); | |
922 EXPECT_FALSE(layer2->didDrawCalled()); | |
923 | |
924 CCLayerTreeHostImpl::FrameData frame; | |
925 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
926 m_hostImpl->drawLayers(frame); | |
927 m_hostImpl->didDrawAllLayers(frame); | |
928 | |
929 EXPECT_TRUE(root->didDrawCalled()); | |
930 EXPECT_TRUE(layer1->didDrawCalled()); | |
931 EXPECT_TRUE(layer2->didDrawCalled()); | |
932 | |
933 EXPECT_NE(root->renderSurface(), layer1->renderSurface()); | |
934 EXPECT_TRUE(!!layer1->renderSurface()); | |
935 } | |
936 | |
937 class MissingTextureAnimatingLayer : public DidDrawCheckLayer { | |
938 public: | |
939 static scoped_ptr<CCLayerImpl> create(int id, bool tileMissing, bool skipsDr
aw, bool animating, CCResourceProvider* resourceProvider) | |
940 { | |
941 return scoped_ptr<CCLayerImpl>(new MissingTextureAnimatingLayer(id, tile
Missing, skipsDraw, animating, resourceProvider)); | |
942 } | |
943 | |
944 private: | |
945 explicit MissingTextureAnimatingLayer(int id, bool tileMissing, bool skipsDr
aw, bool animating, CCResourceProvider* resourceProvider) | |
946 : DidDrawCheckLayer(id) | |
947 { | |
948 OwnPtr<CCLayerTilingData> tilingData = CCLayerTilingData::create(IntSize
(10, 10), CCLayerTilingData::NoBorderTexels); | |
949 tilingData->setBounds(bounds()); | |
950 setTilingData(*tilingData.get()); | |
951 setSkipsDraw(skipsDraw); | |
952 if (!tileMissing) { | |
953 CCResourceProvider::ResourceId resource = resourceProvider->createRe
source(CCRenderer::ContentPool, IntSize(), GraphicsContext3D::RGBA, CCResourcePr
ovider::TextureUsageAny); | |
954 pushTileProperties(0, 0, resource, IntRect()); | |
955 } | |
956 if (animating) | |
957 addAnimatedTransformToLayer(*this, 10, 3, 0); | |
958 } | |
959 }; | |
960 | |
961 TEST_P(CCLayerTreeHostImplTest, prepareToDrawFailsWhenAnimationUsesCheckerboard) | |
962 { | |
963 // When the texture is not missing, we draw as usual. | |
964 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); | |
965 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLa
yer()); | |
966 root->addChild(MissingTextureAnimatingLayer::create(2, false, false, true, m
_hostImpl->resourceProvider())); | |
967 | |
968 CCLayerTreeHostImpl::FrameData frame; | |
969 | |
970 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
971 m_hostImpl->drawLayers(frame); | |
972 m_hostImpl->didDrawAllLayers(frame); | |
973 | |
974 // When a texture is missing and we're not animating, we draw as usual with
checkerboarding. | |
975 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); | |
976 root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); | |
977 root->addChild(MissingTextureAnimatingLayer::create(2, true, false, false, m
_hostImpl->resourceProvider())); | |
978 | |
979 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
980 m_hostImpl->drawLayers(frame); | |
981 m_hostImpl->didDrawAllLayers(frame); | |
982 | |
983 // When a texture is missing and we're animating, we don't want to draw anyt
hing. | |
984 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); | |
985 root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); | |
986 root->addChild(MissingTextureAnimatingLayer::create(2, true, false, true, m_
hostImpl->resourceProvider())); | |
987 | |
988 EXPECT_FALSE(m_hostImpl->prepareToDraw(frame)); | |
989 m_hostImpl->drawLayers(frame); | |
990 m_hostImpl->didDrawAllLayers(frame); | |
991 | |
992 // When the layer skips draw and we're animating, we still draw the frame. | |
993 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1)); | |
994 root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer()); | |
995 root->addChild(MissingTextureAnimatingLayer::create(2, false, true, true, m_
hostImpl->resourceProvider())); | |
996 | |
997 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
998 m_hostImpl->drawLayers(frame); | |
999 m_hostImpl->didDrawAllLayers(frame); | |
1000 } | |
1001 | |
1002 TEST_P(CCLayerTreeHostImplTest, scrollRootIgnored) | |
1003 { | |
1004 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
1005 root->setScrollable(false); | |
1006 m_hostImpl->setRootLayer(root.Pass()); | |
1007 initializeRendererAndDrawFrame(); | |
1008 | |
1009 // Scroll event is ignored because layer is not scrollable. | |
1010 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollIgnored); | |
1011 EXPECT_FALSE(m_didRequestRedraw); | |
1012 EXPECT_FALSE(m_didRequestCommit); | |
1013 } | |
1014 | |
1015 TEST_P(CCLayerTreeHostImplTest, scrollNonCompositedRoot) | |
1016 { | |
1017 // Test the configuration where a non-composited root layer is embedded in a | |
1018 // scrollable outer layer. | |
1019 IntSize surfaceSize(10, 10); | |
1020 | |
1021 scoped_ptr<CCLayerImpl> contentLayer = CCLayerImpl::create(1); | |
1022 contentLayer->setUseLCDText(true); | |
1023 contentLayer->setDrawsContent(true); | |
1024 contentLayer->setPosition(FloatPoint(0, 0)); | |
1025 contentLayer->setAnchorPoint(FloatPoint(0, 0)); | |
1026 contentLayer->setBounds(surfaceSize); | |
1027 contentLayer->setContentBounds(IntSize(surfaceSize.width() * 2, surfaceSize.
height() * 2)); | |
1028 | |
1029 scoped_ptr<CCLayerImpl> scrollLayer = CCLayerImpl::create(2); | |
1030 scrollLayer->setScrollable(true); | |
1031 scrollLayer->setMaxScrollPosition(surfaceSize); | |
1032 scrollLayer->setBounds(surfaceSize); | |
1033 scrollLayer->setContentBounds(surfaceSize); | |
1034 scrollLayer->setPosition(FloatPoint(0, 0)); | |
1035 scrollLayer->setAnchorPoint(FloatPoint(0, 0)); | |
1036 scrollLayer->addChild(contentLayer.Pass()); | |
1037 | |
1038 m_hostImpl->setRootLayer(scrollLayer.Pass()); | |
1039 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1040 initializeRendererAndDrawFrame(); | |
1041 | |
1042 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
1043 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); | |
1044 m_hostImpl->scrollEnd(); | |
1045 EXPECT_TRUE(m_didRequestRedraw); | |
1046 EXPECT_TRUE(m_didRequestCommit); | |
1047 } | |
1048 | |
1049 TEST_P(CCLayerTreeHostImplTest, scrollChildCallsCommitAndRedraw) | |
1050 { | |
1051 IntSize surfaceSize(10, 10); | |
1052 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
1053 root->setBounds(surfaceSize); | |
1054 root->setContentBounds(surfaceSize); | |
1055 root->addChild(createScrollableLayer(2, surfaceSize)); | |
1056 m_hostImpl->setRootLayer(root.Pass()); | |
1057 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1058 initializeRendererAndDrawFrame(); | |
1059 | |
1060 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
1061 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10)); | |
1062 m_hostImpl->scrollEnd(); | |
1063 EXPECT_TRUE(m_didRequestRedraw); | |
1064 EXPECT_TRUE(m_didRequestCommit); | |
1065 } | |
1066 | |
1067 TEST_P(CCLayerTreeHostImplTest, scrollMissesChild) | |
1068 { | |
1069 IntSize surfaceSize(10, 10); | |
1070 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
1071 root->addChild(createScrollableLayer(2, surfaceSize)); | |
1072 m_hostImpl->setRootLayer(root.Pass()); | |
1073 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1074 initializeRendererAndDrawFrame(); | |
1075 | |
1076 // Scroll event is ignored because the input coordinate is outside the layer
boundaries. | |
1077 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(15, 5), CCInputHandlerClient::Whe
el), CCInputHandlerClient::ScrollIgnored); | |
1078 EXPECT_FALSE(m_didRequestRedraw); | |
1079 EXPECT_FALSE(m_didRequestCommit); | |
1080 } | |
1081 | |
1082 TEST_P(CCLayerTreeHostImplTest, scrollMissesBackfacingChild) | |
1083 { | |
1084 IntSize surfaceSize(10, 10); | |
1085 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
1086 scoped_ptr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize); | |
1087 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1088 | |
1089 WebTransformationMatrix matrix; | |
1090 matrix.rotate3d(180, 0, 0); | |
1091 child->setTransform(matrix); | |
1092 child->setDoubleSided(false); | |
1093 | |
1094 root->addChild(child.Pass()); | |
1095 m_hostImpl->setRootLayer(root.Pass()); | |
1096 initializeRendererAndDrawFrame(); | |
1097 | |
1098 // Scroll event is ignored because the scrollable layer is not facing the vi
ewer and there is | |
1099 // nothing scrollable behind it. | |
1100 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollIgnored); | |
1101 EXPECT_FALSE(m_didRequestRedraw); | |
1102 EXPECT_FALSE(m_didRequestCommit); | |
1103 } | |
1104 | |
1105 TEST_P(CCLayerTreeHostImplTest, scrollBlockedByContentLayer) | |
1106 { | |
1107 IntSize surfaceSize(10, 10); | |
1108 scoped_ptr<CCLayerImpl> contentLayer = createScrollableLayer(1, surfaceSize)
; | |
1109 contentLayer->setShouldScrollOnMainThread(true); | |
1110 contentLayer->setScrollable(false); | |
1111 | |
1112 scoped_ptr<CCLayerImpl> scrollLayer = createScrollableLayer(2, surfaceSize); | |
1113 scrollLayer->addChild(contentLayer.Pass()); | |
1114 | |
1115 m_hostImpl->setRootLayer(scrollLayer.Pass()); | |
1116 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1117 initializeRendererAndDrawFrame(); | |
1118 | |
1119 // Scrolling fails because the content layer is asking to be scrolled on the
main thread. | |
1120 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollOnMainThread); | |
1121 } | |
1122 | |
1123 TEST_P(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnMainThread) | |
1124 { | |
1125 IntSize surfaceSize(10, 10); | |
1126 float pageScale = 2; | |
1127 scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize); | |
1128 m_hostImpl->setRootLayer(root.Pass()); | |
1129 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1130 initializeRendererAndDrawFrame(); | |
1131 | |
1132 IntSize scrollDelta(0, 10); | |
1133 IntSize expectedScrollDelta(scrollDelta); | |
1134 IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition()); | |
1135 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
1136 m_hostImpl->scrollBy(IntPoint(), scrollDelta); | |
1137 m_hostImpl->scrollEnd(); | |
1138 | |
1139 // Set new page scale from main thread. | |
1140 m_hostImpl->setPageScaleFactorAndLimits(pageScale, pageScale, pageScale); | |
1141 | |
1142 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
1143 // The scale should apply to the scroll delta. | |
1144 expectedScrollDelta.scale(pageScale); | |
1145 } | |
1146 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas
(); | |
1147 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScr
ollDelta); | |
1148 | |
1149 // The scroll range should also have been updated. | |
1150 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll); | |
1151 | |
1152 // The page scale delta remains constant because the impl thread did not sca
le. | |
1153 EXPECT_EQ(m_hostImpl->rootLayer()->implTransform(), WebTransformationMatrix(
)); | |
1154 } | |
1155 | |
1156 TEST_P(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnImplThread) | |
1157 { | |
1158 IntSize surfaceSize(10, 10); | |
1159 float pageScale = 2; | |
1160 scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize); | |
1161 m_hostImpl->setRootLayer(root.Pass()); | |
1162 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1163 m_hostImpl->setPageScaleFactorAndLimits(1, 1, pageScale); | |
1164 initializeRendererAndDrawFrame(); | |
1165 | |
1166 IntSize scrollDelta(0, 10); | |
1167 IntSize expectedScrollDelta(scrollDelta); | |
1168 IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition()); | |
1169 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
1170 m_hostImpl->scrollBy(IntPoint(), scrollDelta); | |
1171 m_hostImpl->scrollEnd(); | |
1172 | |
1173 // Set new page scale on impl thread by pinching. | |
1174 m_hostImpl->pinchGestureBegin(); | |
1175 m_hostImpl->pinchGestureUpdate(pageScale, IntPoint()); | |
1176 m_hostImpl->pinchGestureEnd(); | |
1177 m_hostImpl->updateRootScrollLayerImplTransform(); | |
1178 | |
1179 // The scroll delta is not scaled because the main thread did not scale. | |
1180 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas
(); | |
1181 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScr
ollDelta); | |
1182 | |
1183 // The scroll range should also have been updated. | |
1184 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll); | |
1185 | |
1186 // The page scale delta should match the new scale on the impl side. | |
1187 WebTransformationMatrix expectedScale; | |
1188 expectedScale.scale(pageScale); | |
1189 EXPECT_EQ(m_hostImpl->rootLayer()->implTransform(), expectedScale); | |
1190 } | |
1191 | |
1192 TEST_P(CCLayerTreeHostImplTest, pageScaleDeltaAppliedToRootScrollLayerOnly) | |
1193 { | |
1194 IntSize surfaceSize(10, 10); | |
1195 float defaultPageScale = 1; | |
1196 WebTransformationMatrix defaultPageScaleMatrix; | |
1197 | |
1198 float newPageScale = 2; | |
1199 WebTransformationMatrix newPageScaleMatrix; | |
1200 newPageScaleMatrix.scale(newPageScale); | |
1201 | |
1202 // Create a normal scrollable root layer and another scrollable child layer. | |
1203 setupScrollAndContentsLayers(surfaceSize); | |
1204 CCLayerImpl* root = m_hostImpl->rootLayer(); | |
1205 CCLayerImpl* child = root->children()[0]; | |
1206 | |
1207 scoped_ptr<CCLayerImpl> scrollableChild = createScrollableLayer(3, surfaceSi
ze); | |
1208 child->addChild(scrollableChild.Pass()); | |
1209 CCLayerImpl* grandChild = child->children()[0]; | |
1210 | |
1211 // Set new page scale on impl thread by pinching. | |
1212 m_hostImpl->pinchGestureBegin(); | |
1213 m_hostImpl->pinchGestureUpdate(newPageScale, IntPoint()); | |
1214 m_hostImpl->pinchGestureEnd(); | |
1215 m_hostImpl->updateRootScrollLayerImplTransform(); | |
1216 | |
1217 // The page scale delta should only be applied to the scrollable root layer. | |
1218 EXPECT_EQ(root->implTransform(), newPageScaleMatrix); | |
1219 EXPECT_EQ(child->implTransform(), defaultPageScaleMatrix); | |
1220 EXPECT_EQ(grandChild->implTransform(), defaultPageScaleMatrix); | |
1221 | |
1222 // Make sure all the layers are drawn with the page scale delta applied, i.e
., the page scale | |
1223 // delta on the root layer is applied hierarchically. | |
1224 CCLayerTreeHostImpl::FrameData frame; | |
1225 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1226 m_hostImpl->drawLayers(frame); | |
1227 m_hostImpl->didDrawAllLayers(frame); | |
1228 | |
1229 EXPECT_EQ(root->drawTransform().m11(), newPageScale); | |
1230 EXPECT_EQ(root->drawTransform().m22(), newPageScale); | |
1231 EXPECT_EQ(child->drawTransform().m11(), newPageScale); | |
1232 EXPECT_EQ(child->drawTransform().m22(), newPageScale); | |
1233 EXPECT_EQ(grandChild->drawTransform().m11(), newPageScale); | |
1234 EXPECT_EQ(grandChild->drawTransform().m22(), newPageScale); | |
1235 } | |
1236 | |
1237 TEST_P(CCLayerTreeHostImplTest, scrollChildAndChangePageScaleOnMainThread) | |
1238 { | |
1239 IntSize surfaceSize(10, 10); | |
1240 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
1241 root->setBounds(surfaceSize); | |
1242 root->setContentBounds(surfaceSize); | |
1243 // Also mark the root scrollable so it becomes the root scroll layer. | |
1244 root->setScrollable(true); | |
1245 int scrollLayerId = 2; | |
1246 root->addChild(createScrollableLayer(scrollLayerId, surfaceSize)); | |
1247 m_hostImpl->setRootLayer(root.Pass()); | |
1248 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1249 initializeRendererAndDrawFrame(); | |
1250 | |
1251 CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0]; | |
1252 | |
1253 IntSize scrollDelta(0, 10); | |
1254 IntSize expectedScrollDelta(scrollDelta); | |
1255 IntSize expectedMaxScroll(child->maxScrollPosition()); | |
1256 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
1257 m_hostImpl->scrollBy(IntPoint(), scrollDelta); | |
1258 m_hostImpl->scrollEnd(); | |
1259 | |
1260 float pageScale = 2; | |
1261 m_hostImpl->setPageScaleFactorAndLimits(pageScale, 1, pageScale); | |
1262 | |
1263 m_hostImpl->updateRootScrollLayerImplTransform(); | |
1264 | |
1265 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
1266 // The scale should apply to the scroll delta. | |
1267 expectedScrollDelta.scale(pageScale); | |
1268 } | |
1269 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas
(); | |
1270 expectContains(*scrollInfo.get(), scrollLayerId, expectedScrollDelta); | |
1271 | |
1272 // The scroll range should not have changed. | |
1273 EXPECT_EQ(child->maxScrollPosition(), expectedMaxScroll); | |
1274 | |
1275 // The page scale delta remains constant because the impl thread did not sca
le. | |
1276 WebTransformationMatrix identityTransform; | |
1277 EXPECT_EQ(child->implTransform(), WebTransformationMatrix()); | |
1278 } | |
1279 | |
1280 TEST_P(CCLayerTreeHostImplTest, scrollChildBeyondLimit) | |
1281 { | |
1282 // Scroll a child layer beyond its maximum scroll range and make sure the | |
1283 // parent layer is scrolled on the axis on which the child was unable to | |
1284 // scroll. | |
1285 IntSize surfaceSize(10, 10); | |
1286 scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize); | |
1287 | |
1288 scoped_ptr<CCLayerImpl> grandChild = createScrollableLayer(3, surfaceSize); | |
1289 grandChild->setScrollPosition(IntPoint(0, 5)); | |
1290 | |
1291 scoped_ptr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize); | |
1292 child->setScrollPosition(IntPoint(3, 0)); | |
1293 child->addChild(grandChild.Pass()); | |
1294 | |
1295 root->addChild(child.Pass()); | |
1296 m_hostImpl->setRootLayer(root.Pass()); | |
1297 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1298 initializeRendererAndDrawFrame(); | |
1299 { | |
1300 IntSize scrollDelta(-8, -7); | |
1301 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::
Wheel), CCInputHandlerClient::ScrollStarted); | |
1302 m_hostImpl->scrollBy(IntPoint(), scrollDelta); | |
1303 m_hostImpl->scrollEnd(); | |
1304 | |
1305 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
1306 | |
1307 // The grand child should have scrolled up to its limit. | |
1308 CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0]; | |
1309 CCLayerImpl* grandChild = child->children()[0]; | |
1310 expectContains(*scrollInfo.get(), grandChild->id(), IntSize(0, -5)); | |
1311 | |
1312 // The child should have only scrolled on the other axis. | |
1313 expectContains(*scrollInfo.get(), child->id(), IntSize(-3, 0)); | |
1314 } | |
1315 } | |
1316 | |
1317 TEST_P(CCLayerTreeHostImplTest, scrollEventBubbling) | |
1318 { | |
1319 // When we try to scroll a non-scrollable child layer, the scroll delta | |
1320 // should be applied to one of its ancestors if possible. | |
1321 IntSize surfaceSize(10, 10); | |
1322 scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize); | |
1323 scoped_ptr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize); | |
1324 | |
1325 child->setScrollable(false); | |
1326 root->addChild(child.Pass()); | |
1327 | |
1328 m_hostImpl->setRootLayer(root.Pass()); | |
1329 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1330 initializeRendererAndDrawFrame(); | |
1331 { | |
1332 IntSize scrollDelta(0, 4); | |
1333 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::
Wheel), CCInputHandlerClient::ScrollStarted); | |
1334 m_hostImpl->scrollBy(IntPoint(), scrollDelta); | |
1335 m_hostImpl->scrollEnd(); | |
1336 | |
1337 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
1338 | |
1339 // Only the root should have scrolled. | |
1340 ASSERT_EQ(scrollInfo->scrolls.size(), 1u); | |
1341 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), scrollD
elta); | |
1342 } | |
1343 } | |
1344 | |
1345 TEST_P(CCLayerTreeHostImplTest, scrollBeforeRedraw) | |
1346 { | |
1347 IntSize surfaceSize(10, 10); | |
1348 m_hostImpl->setRootLayer(createScrollableLayer(1, surfaceSize)); | |
1349 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1350 | |
1351 // Draw one frame and then immediately rebuild the layer tree to mimic a tre
e synchronization. | |
1352 initializeRendererAndDrawFrame(); | |
1353 m_hostImpl->detachLayerTree(); | |
1354 m_hostImpl->setRootLayer(createScrollableLayer(2, surfaceSize)); | |
1355 | |
1356 // Scrolling should still work even though we did not draw yet. | |
1357 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
1358 } | |
1359 | |
1360 TEST_P(CCLayerTreeHostImplTest, scrollAxisAlignedRotatedLayer) | |
1361 { | |
1362 setupScrollAndContentsLayers(IntSize(100, 100)); | |
1363 | |
1364 // Rotate the root layer 90 degrees counter-clockwise about its center. | |
1365 WebTransformationMatrix rotateTransform; | |
1366 rotateTransform.rotate(-90); | |
1367 m_hostImpl->rootLayer()->setTransform(rotateTransform); | |
1368 | |
1369 IntSize surfaceSize(50, 50); | |
1370 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1371 initializeRendererAndDrawFrame(); | |
1372 | |
1373 // Scroll to the right in screen coordinates with a gesture. | |
1374 IntSize gestureScrollDelta(10, 0); | |
1375 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gest
ure), CCInputHandlerClient::ScrollStarted); | |
1376 m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta); | |
1377 m_hostImpl->scrollEnd(); | |
1378 | |
1379 // The layer should have scrolled down in its local coordinates. | |
1380 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas
(); | |
1381 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), IntSize(0,
gestureScrollDelta.width())); | |
1382 | |
1383 // Reset and scroll down with the wheel. | |
1384 m_hostImpl->rootLayer()->setScrollDelta(FloatSize()); | |
1385 IntSize wheelScrollDelta(0, 10); | |
1386 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
1387 m_hostImpl->scrollBy(IntPoint(), wheelScrollDelta); | |
1388 m_hostImpl->scrollEnd(); | |
1389 | |
1390 // The layer should have scrolled down in its local coordinates. | |
1391 scrollInfo = m_hostImpl->processScrollDeltas(); | |
1392 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), wheelScroll
Delta); | |
1393 } | |
1394 | |
1395 TEST_P(CCLayerTreeHostImplTest, scrollNonAxisAlignedRotatedLayer) | |
1396 { | |
1397 setupScrollAndContentsLayers(IntSize(100, 100)); | |
1398 int childLayerId = 3; | |
1399 float childLayerAngle = -20; | |
1400 | |
1401 // Create a child layer that is rotated to a non-axis-aligned angle. | |
1402 scoped_ptr<CCLayerImpl> child = createScrollableLayer(childLayerId, m_hostIm
pl->rootLayer()->contentBounds()); | |
1403 WebTransformationMatrix rotateTransform; | |
1404 rotateTransform.translate(-50, -50); | |
1405 rotateTransform.rotate(childLayerAngle); | |
1406 rotateTransform.translate(50, 50); | |
1407 child->setTransform(rotateTransform); | |
1408 | |
1409 // Only allow vertical scrolling. | |
1410 child->setMaxScrollPosition(IntSize(0, child->contentBounds().height())); | |
1411 m_hostImpl->rootLayer()->addChild(child.Pass()); | |
1412 | |
1413 IntSize surfaceSize(50, 50); | |
1414 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1415 initializeRendererAndDrawFrame(); | |
1416 | |
1417 { | |
1418 // Scroll down in screen coordinates with a gesture. | |
1419 IntSize gestureScrollDelta(0, 10); | |
1420 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::
Gesture), CCInputHandlerClient::ScrollStarted); | |
1421 m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta); | |
1422 m_hostImpl->scrollEnd(); | |
1423 | |
1424 // The child layer should have scrolled down in its local coordinates an
amount proportional to | |
1425 // the angle between it and the input scroll delta. | |
1426 IntSize expectedScrollDelta(0, gestureScrollDelta.height() * cosf(deg2ra
d(childLayerAngle))); | |
1427 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
1428 expectContains(*scrollInfo.get(), childLayerId, expectedScrollDelta); | |
1429 | |
1430 // The root layer should not have scrolled, because the input delta was
close to the layer's | |
1431 // axis of movement. | |
1432 EXPECT_EQ(scrollInfo->scrolls.size(), 1u); | |
1433 } | |
1434 | |
1435 { | |
1436 // Now reset and scroll the same amount horizontally. | |
1437 m_hostImpl->rootLayer()->children()[1]->setScrollDelta(FloatSize()); | |
1438 IntSize gestureScrollDelta(10, 0); | |
1439 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::
Gesture), CCInputHandlerClient::ScrollStarted); | |
1440 m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta); | |
1441 m_hostImpl->scrollEnd(); | |
1442 | |
1443 // The child layer should have scrolled down in its local coordinates an
amount proportional to | |
1444 // the angle between it and the input scroll delta. | |
1445 IntSize expectedScrollDelta(0, -gestureScrollDelta.width() * sinf(deg2ra
d(childLayerAngle))); | |
1446 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe
ltas(); | |
1447 expectContains(*scrollInfo.get(), childLayerId, expectedScrollDelta); | |
1448 | |
1449 // The root layer should have scrolled more, since the input scroll delt
a was mostly | |
1450 // orthogonal to the child layer's vertical scroll axis. | |
1451 IntSize expectedRootScrollDelta(gestureScrollDelta.width() * pow(cosf(de
g2rad(childLayerAngle)), 2), 0); | |
1452 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expecte
dRootScrollDelta); | |
1453 } | |
1454 } | |
1455 | |
1456 TEST_P(CCLayerTreeHostImplTest, scrollScaledLayer) | |
1457 { | |
1458 setupScrollAndContentsLayers(IntSize(100, 100)); | |
1459 | |
1460 // Scale the layer to twice its normal size. | |
1461 int scale = 2; | |
1462 WebTransformationMatrix scaleTransform; | |
1463 scaleTransform.scale(scale); | |
1464 m_hostImpl->rootLayer()->setTransform(scaleTransform); | |
1465 | |
1466 IntSize surfaceSize(50, 50); | |
1467 m_hostImpl->setViewportSize(surfaceSize, surfaceSize); | |
1468 initializeRendererAndDrawFrame(); | |
1469 | |
1470 // Scroll down in screen coordinates with a gesture. | |
1471 IntSize scrollDelta(0, 10); | |
1472 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gest
ure), CCInputHandlerClient::ScrollStarted); | |
1473 m_hostImpl->scrollBy(IntPoint(), scrollDelta); | |
1474 m_hostImpl->scrollEnd(); | |
1475 | |
1476 // The layer should have scrolled down in its local coordinates, but half he
amount. | |
1477 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas
(); | |
1478 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), IntSize(0,
scrollDelta.height() / scale)); | |
1479 | |
1480 // Reset and scroll down with the wheel. | |
1481 m_hostImpl->rootLayer()->setScrollDelta(FloatSize()); | |
1482 IntSize wheelScrollDelta(0, 10); | |
1483 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee
l), CCInputHandlerClient::ScrollStarted); | |
1484 m_hostImpl->scrollBy(IntPoint(), wheelScrollDelta); | |
1485 m_hostImpl->scrollEnd(); | |
1486 | |
1487 // The scale should not have been applied to the scroll delta. | |
1488 scrollInfo = m_hostImpl->processScrollDeltas(); | |
1489 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), wheelScroll
Delta); | |
1490 } | |
1491 | |
1492 class BlendStateTrackerContext: public FakeWebGraphicsContext3D { | |
1493 public: | |
1494 BlendStateTrackerContext() : m_blend(false) { } | |
1495 | |
1496 virtual void enable(WGC3Denum cap) | |
1497 { | |
1498 if (cap == GraphicsContext3D::BLEND) | |
1499 m_blend = true; | |
1500 } | |
1501 | |
1502 virtual void disable(WGC3Denum cap) | |
1503 { | |
1504 if (cap == GraphicsContext3D::BLEND) | |
1505 m_blend = false; | |
1506 } | |
1507 | |
1508 bool blend() const { return m_blend; } | |
1509 | |
1510 private: | |
1511 bool m_blend; | |
1512 }; | |
1513 | |
1514 class BlendStateCheckLayer : public CCLayerImpl { | |
1515 public: | |
1516 static scoped_ptr<CCLayerImpl> create(int id, CCResourceProvider* resourcePr
ovider) { return scoped_ptr<CCLayerImpl>(new BlendStateCheckLayer(id, resourcePr
ovider)); } | |
1517 | |
1518 virtual void appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuad
sData) OVERRIDE | |
1519 { | |
1520 m_quadsAppended = true; | |
1521 | |
1522 IntRect opaqueRect; | |
1523 if (contentsOpaque()) | |
1524 opaqueRect = m_quadRect; | |
1525 else | |
1526 opaqueRect = m_opaqueContentRect; | |
1527 | |
1528 CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createS
haredQuadState()); | |
1529 scoped_ptr<CCTileDrawQuad> testBlendingDrawQuad = CCTileDrawQuad::create
(sharedQuadState, m_quadRect, opaqueRect, m_resourceId, IntPoint(), IntSize(1, 1
), 0, false, false, false, false, false); | |
1530 testBlendingDrawQuad->setQuadVisibleRect(m_quadVisibleRect); | |
1531 EXPECT_EQ(m_blend, testBlendingDrawQuad->needsBlending()); | |
1532 EXPECT_EQ(m_hasRenderSurface, !!renderSurface()); | |
1533 quadSink.append(testBlendingDrawQuad.PassAs<CCDrawQuad>(), appendQuadsDa
ta); | |
1534 } | |
1535 | |
1536 void setExpectation(bool blend, bool hasRenderSurface) | |
1537 { | |
1538 m_blend = blend; | |
1539 m_hasRenderSurface = hasRenderSurface; | |
1540 m_quadsAppended = false; | |
1541 } | |
1542 | |
1543 bool quadsAppended() const { return m_quadsAppended; } | |
1544 | |
1545 void setQuadRect(const IntRect& rect) { m_quadRect = rect; } | |
1546 void setQuadVisibleRect(const IntRect& rect) { m_quadVisibleRect = rect; } | |
1547 void setOpaqueContentRect(const IntRect& rect) { m_opaqueContentRect = rect;
} | |
1548 | |
1549 private: | |
1550 explicit BlendStateCheckLayer(int id, CCResourceProvider* resourceProvider) | |
1551 : CCLayerImpl(id) | |
1552 , m_blend(false) | |
1553 , m_hasRenderSurface(false) | |
1554 , m_quadsAppended(false) | |
1555 , m_quadRect(5, 5, 5, 5) | |
1556 , m_quadVisibleRect(5, 5, 5, 5) | |
1557 , m_resourceId(resourceProvider->createResource(CCRenderer::ContentPool,
IntSize(1, 1), GraphicsContext3D::RGBA, CCResourceProvider::TextureUsageAny)) | |
1558 { | |
1559 setAnchorPoint(FloatPoint(0, 0)); | |
1560 setBounds(IntSize(10, 10)); | |
1561 setContentBounds(IntSize(10, 10)); | |
1562 setDrawsContent(true); | |
1563 } | |
1564 | |
1565 bool m_blend; | |
1566 bool m_hasRenderSurface; | |
1567 bool m_quadsAppended; | |
1568 IntRect m_quadRect; | |
1569 IntRect m_opaqueContentRect; | |
1570 IntRect m_quadVisibleRect; | |
1571 CCResourceProvider::ResourceId m_resourceId; | |
1572 }; | |
1573 | |
1574 TEST_P(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers) | |
1575 { | |
1576 { | |
1577 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
1578 root->setAnchorPoint(FloatPoint(0, 0)); | |
1579 root->setBounds(IntSize(10, 10)); | |
1580 root->setContentBounds(root->bounds()); | |
1581 root->setDrawsContent(false); | |
1582 m_hostImpl->setRootLayer(root.Pass()); | |
1583 } | |
1584 CCLayerImpl* root = m_hostImpl->rootLayer(); | |
1585 | |
1586 root->addChild(BlendStateCheckLayer::create(2, m_hostImpl->resourceProvider(
))); | |
1587 BlendStateCheckLayer* layer1 = static_cast<BlendStateCheckLayer*>(root->chil
dren()[0]); | |
1588 layer1->setPosition(FloatPoint(2, 2)); | |
1589 | |
1590 CCLayerTreeHostImpl::FrameData frame; | |
1591 | |
1592 // Opaque layer, drawn without blending. | |
1593 layer1->setContentsOpaque(true); | |
1594 layer1->setExpectation(false, false); | |
1595 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1596 m_hostImpl->drawLayers(frame); | |
1597 EXPECT_TRUE(layer1->quadsAppended()); | |
1598 m_hostImpl->didDrawAllLayers(frame); | |
1599 | |
1600 // Layer with translucent content and painting, so drawn with blending. | |
1601 layer1->setContentsOpaque(false); | |
1602 layer1->setExpectation(true, false); | |
1603 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1604 m_hostImpl->drawLayers(frame); | |
1605 EXPECT_TRUE(layer1->quadsAppended()); | |
1606 m_hostImpl->didDrawAllLayers(frame); | |
1607 | |
1608 // Layer with translucent opacity, drawn with blending. | |
1609 layer1->setContentsOpaque(true); | |
1610 layer1->setOpacity(0.5); | |
1611 layer1->setExpectation(true, false); | |
1612 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1613 m_hostImpl->drawLayers(frame); | |
1614 EXPECT_TRUE(layer1->quadsAppended()); | |
1615 m_hostImpl->didDrawAllLayers(frame); | |
1616 | |
1617 // Layer with translucent opacity and painting, drawn with blending. | |
1618 layer1->setContentsOpaque(true); | |
1619 layer1->setOpacity(0.5); | |
1620 layer1->setExpectation(true, false); | |
1621 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1622 m_hostImpl->drawLayers(frame); | |
1623 EXPECT_TRUE(layer1->quadsAppended()); | |
1624 m_hostImpl->didDrawAllLayers(frame); | |
1625 | |
1626 layer1->addChild(BlendStateCheckLayer::create(3, m_hostImpl->resourceProvide
r())); | |
1627 BlendStateCheckLayer* layer2 = static_cast<BlendStateCheckLayer*>(layer1->ch
ildren()[0]); | |
1628 layer2->setPosition(FloatPoint(4, 4)); | |
1629 | |
1630 // 2 opaque layers, drawn without blending. | |
1631 layer1->setContentsOpaque(true); | |
1632 layer1->setOpacity(1); | |
1633 layer1->setExpectation(false, false); | |
1634 layer2->setContentsOpaque(true); | |
1635 layer2->setOpacity(1); | |
1636 layer2->setExpectation(false, false); | |
1637 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1638 m_hostImpl->drawLayers(frame); | |
1639 EXPECT_TRUE(layer1->quadsAppended()); | |
1640 EXPECT_TRUE(layer2->quadsAppended()); | |
1641 m_hostImpl->didDrawAllLayers(frame); | |
1642 | |
1643 // Parent layer with translucent content, drawn with blending. | |
1644 // Child layer with opaque content, drawn without blending. | |
1645 layer1->setContentsOpaque(false); | |
1646 layer1->setExpectation(true, false); | |
1647 layer2->setExpectation(false, false); | |
1648 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1649 m_hostImpl->drawLayers(frame); | |
1650 EXPECT_TRUE(layer1->quadsAppended()); | |
1651 EXPECT_TRUE(layer2->quadsAppended()); | |
1652 m_hostImpl->didDrawAllLayers(frame); | |
1653 | |
1654 // Parent layer with translucent content but opaque painting, drawn without
blending. | |
1655 // Child layer with opaque content, drawn without blending. | |
1656 layer1->setContentsOpaque(true); | |
1657 layer1->setExpectation(false, false); | |
1658 layer2->setExpectation(false, false); | |
1659 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1660 m_hostImpl->drawLayers(frame); | |
1661 EXPECT_TRUE(layer1->quadsAppended()); | |
1662 EXPECT_TRUE(layer2->quadsAppended()); | |
1663 m_hostImpl->didDrawAllLayers(frame); | |
1664 | |
1665 // Parent layer with translucent opacity and opaque content. Since it has a | |
1666 // drawing child, it's drawn to a render surface which carries the opacity, | |
1667 // so it's itself drawn without blending. | |
1668 // Child layer with opaque content, drawn without blending (parent surface | |
1669 // carries the inherited opacity). | |
1670 layer1->setContentsOpaque(true); | |
1671 layer1->setOpacity(0.5); | |
1672 layer1->setExpectation(false, true); | |
1673 layer2->setExpectation(false, false); | |
1674 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1675 m_hostImpl->drawLayers(frame); | |
1676 EXPECT_TRUE(layer1->quadsAppended()); | |
1677 EXPECT_TRUE(layer2->quadsAppended()); | |
1678 m_hostImpl->didDrawAllLayers(frame); | |
1679 | |
1680 // Draw again, but with child non-opaque, to make sure | |
1681 // layer1 not culled. | |
1682 layer1->setContentsOpaque(true); | |
1683 layer1->setOpacity(1); | |
1684 layer1->setExpectation(false, false); | |
1685 layer2->setContentsOpaque(true); | |
1686 layer2->setOpacity(0.5); | |
1687 layer2->setExpectation(true, false); | |
1688 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1689 m_hostImpl->drawLayers(frame); | |
1690 EXPECT_TRUE(layer1->quadsAppended()); | |
1691 EXPECT_TRUE(layer2->quadsAppended()); | |
1692 m_hostImpl->didDrawAllLayers(frame); | |
1693 | |
1694 // A second way of making the child non-opaque. | |
1695 layer1->setContentsOpaque(true); | |
1696 layer1->setOpacity(1); | |
1697 layer1->setExpectation(false, false); | |
1698 layer2->setContentsOpaque(false); | |
1699 layer2->setOpacity(1); | |
1700 layer2->setExpectation(true, false); | |
1701 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1702 m_hostImpl->drawLayers(frame); | |
1703 EXPECT_TRUE(layer1->quadsAppended()); | |
1704 EXPECT_TRUE(layer2->quadsAppended()); | |
1705 m_hostImpl->didDrawAllLayers(frame); | |
1706 | |
1707 // And when the layer says its not opaque but is painted opaque, it is not b
lended. | |
1708 layer1->setContentsOpaque(true); | |
1709 layer1->setOpacity(1); | |
1710 layer1->setExpectation(false, false); | |
1711 layer2->setContentsOpaque(true); | |
1712 layer2->setOpacity(1); | |
1713 layer2->setExpectation(false, false); | |
1714 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1715 m_hostImpl->drawLayers(frame); | |
1716 EXPECT_TRUE(layer1->quadsAppended()); | |
1717 EXPECT_TRUE(layer2->quadsAppended()); | |
1718 m_hostImpl->didDrawAllLayers(frame); | |
1719 | |
1720 // Layer with partially opaque contents, drawn with blending. | |
1721 layer1->setContentsOpaque(false); | |
1722 layer1->setQuadRect(IntRect(5, 5, 5, 5)); | |
1723 layer1->setQuadVisibleRect(IntRect(5, 5, 5, 5)); | |
1724 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); | |
1725 layer1->setExpectation(true, false); | |
1726 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1727 m_hostImpl->drawLayers(frame); | |
1728 EXPECT_TRUE(layer1->quadsAppended()); | |
1729 m_hostImpl->didDrawAllLayers(frame); | |
1730 | |
1731 // Layer with partially opaque contents partially culled, drawn with blendin
g. | |
1732 layer1->setContentsOpaque(false); | |
1733 layer1->setQuadRect(IntRect(5, 5, 5, 5)); | |
1734 layer1->setQuadVisibleRect(IntRect(5, 5, 5, 2)); | |
1735 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); | |
1736 layer1->setExpectation(true, false); | |
1737 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1738 m_hostImpl->drawLayers(frame); | |
1739 EXPECT_TRUE(layer1->quadsAppended()); | |
1740 m_hostImpl->didDrawAllLayers(frame); | |
1741 | |
1742 // Layer with partially opaque contents culled, drawn with blending. | |
1743 layer1->setContentsOpaque(false); | |
1744 layer1->setQuadRect(IntRect(5, 5, 5, 5)); | |
1745 layer1->setQuadVisibleRect(IntRect(7, 5, 3, 5)); | |
1746 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); | |
1747 layer1->setExpectation(true, false); | |
1748 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1749 m_hostImpl->drawLayers(frame); | |
1750 EXPECT_TRUE(layer1->quadsAppended()); | |
1751 m_hostImpl->didDrawAllLayers(frame); | |
1752 | |
1753 // Layer with partially opaque contents and translucent contents culled, dra
wn without blending. | |
1754 layer1->setContentsOpaque(false); | |
1755 layer1->setQuadRect(IntRect(5, 5, 5, 5)); | |
1756 layer1->setQuadVisibleRect(IntRect(5, 5, 2, 5)); | |
1757 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5)); | |
1758 layer1->setExpectation(false, false); | |
1759 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1760 m_hostImpl->drawLayers(frame); | |
1761 EXPECT_TRUE(layer1->quadsAppended()); | |
1762 m_hostImpl->didDrawAllLayers(frame); | |
1763 | |
1764 } | |
1765 | |
1766 TEST_P(CCLayerTreeHostImplTest, viewportCovered) | |
1767 { | |
1768 m_hostImpl->initializeRenderer(createContext()); | |
1769 m_hostImpl->setBackgroundColor(SK_ColorGRAY); | |
1770 | |
1771 IntSize viewportSize(1000, 1000); | |
1772 m_hostImpl->setViewportSize(viewportSize, viewportSize); | |
1773 | |
1774 m_hostImpl->setRootLayer(BlendStateCheckLayer::create(1, m_hostImpl->resourc
eProvider())); | |
1775 BlendStateCheckLayer* root = static_cast<BlendStateCheckLayer*>(m_hostImpl->
rootLayer()); | |
1776 root->setExpectation(false, true); | |
1777 root->setContentsOpaque(true); | |
1778 | |
1779 // No gutter rects | |
1780 { | |
1781 IntRect layerRect(0, 0, 1000, 1000); | |
1782 root->setPosition(layerRect.location()); | |
1783 root->setBounds(layerRect.size()); | |
1784 root->setContentBounds(layerRect.size()); | |
1785 root->setQuadRect(IntRect(IntPoint(), layerRect.size())); | |
1786 root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size())); | |
1787 | |
1788 CCLayerTreeHostImpl::FrameData frame; | |
1789 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1790 ASSERT_EQ(1u, frame.renderPasses.size()); | |
1791 | |
1792 size_t numGutterQuads = 0; | |
1793 for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i) | |
1794 numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material()
== CCDrawQuad::SolidColor) ? 1 : 0; | |
1795 EXPECT_EQ(0u, numGutterQuads); | |
1796 EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size()); | |
1797 | |
1798 verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-
layerRect.location(), viewportSize)); | |
1799 m_hostImpl->didDrawAllLayers(frame); | |
1800 } | |
1801 | |
1802 // Empty visible content area (fullscreen gutter rect) | |
1803 { | |
1804 IntRect layerRect(0, 0, 0, 0); | |
1805 root->setPosition(layerRect.location()); | |
1806 root->setBounds(layerRect.size()); | |
1807 root->setContentBounds(layerRect.size()); | |
1808 root->setQuadRect(IntRect(IntPoint(), layerRect.size())); | |
1809 root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size())); | |
1810 | |
1811 CCLayerTreeHostImpl::FrameData frame; | |
1812 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1813 ASSERT_EQ(1u, frame.renderPasses.size()); | |
1814 m_hostImpl->didDrawAllLayers(frame); | |
1815 | |
1816 size_t numGutterQuads = 0; | |
1817 for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i) | |
1818 numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material()
== CCDrawQuad::SolidColor) ? 1 : 0; | |
1819 EXPECT_EQ(1u, numGutterQuads); | |
1820 EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size()); | |
1821 | |
1822 verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-
layerRect.location(), viewportSize)); | |
1823 m_hostImpl->didDrawAllLayers(frame); | |
1824 } | |
1825 | |
1826 // Content area in middle of clip rect (four surrounding gutter rects) | |
1827 { | |
1828 IntRect layerRect(500, 500, 200, 200); | |
1829 root->setPosition(layerRect.location()); | |
1830 root->setBounds(layerRect.size()); | |
1831 root->setContentBounds(layerRect.size()); | |
1832 root->setQuadRect(IntRect(IntPoint(), layerRect.size())); | |
1833 root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size())); | |
1834 | |
1835 CCLayerTreeHostImpl::FrameData frame; | |
1836 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1837 ASSERT_EQ(1u, frame.renderPasses.size()); | |
1838 | |
1839 size_t numGutterQuads = 0; | |
1840 for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i) | |
1841 numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material()
== CCDrawQuad::SolidColor) ? 1 : 0; | |
1842 EXPECT_EQ(4u, numGutterQuads); | |
1843 EXPECT_EQ(5u, frame.renderPasses[0]->quadList().size()); | |
1844 | |
1845 verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-
layerRect.location(), viewportSize)); | |
1846 m_hostImpl->didDrawAllLayers(frame); | |
1847 } | |
1848 | |
1849 } | |
1850 | |
1851 | |
1852 class ReshapeTrackerContext: public FakeWebGraphicsContext3D { | |
1853 public: | |
1854 ReshapeTrackerContext() : m_reshapeCalled(false) { } | |
1855 | |
1856 virtual void reshape(int width, int height) | |
1857 { | |
1858 m_reshapeCalled = true; | |
1859 } | |
1860 | |
1861 bool reshapeCalled() const { return m_reshapeCalled; } | |
1862 | |
1863 private: | |
1864 bool m_reshapeCalled; | |
1865 }; | |
1866 | |
1867 class FakeDrawableCCLayerImpl: public CCLayerImpl { | |
1868 public: | |
1869 static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImp
l>(new FakeDrawableCCLayerImpl(id)); } | |
1870 protected: | |
1871 explicit FakeDrawableCCLayerImpl(int id) : CCLayerImpl(id) { } | |
1872 }; | |
1873 | |
1874 // Only reshape when we know we are going to draw. Otherwise, the reshape | |
1875 // can leave the window at the wrong size if we never draw and the proper | |
1876 // viewport size is never set. | |
1877 TEST_P(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw) | |
1878 { | |
1879 scoped_ptr<CCGraphicsContext> ccContext = FakeWebCompositorOutputSurface::cr
eate(adoptPtr(new ReshapeTrackerContext)).PassAs<CCGraphicsContext>(); | |
1880 ReshapeTrackerContext* reshapeTracker = static_cast<ReshapeTrackerContext*>(
ccContext->context3D()); | |
1881 m_hostImpl->initializeRenderer(ccContext.Pass()); | |
1882 | |
1883 scoped_ptr<CCLayerImpl> root = FakeDrawableCCLayerImpl::create(1); | |
1884 root->setAnchorPoint(FloatPoint(0, 0)); | |
1885 root->setBounds(IntSize(10, 10)); | |
1886 root->setDrawsContent(true); | |
1887 m_hostImpl->setRootLayer(root.Pass()); | |
1888 EXPECT_FALSE(reshapeTracker->reshapeCalled()); | |
1889 | |
1890 CCLayerTreeHostImpl::FrameData frame; | |
1891 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
1892 m_hostImpl->drawLayers(frame); | |
1893 EXPECT_TRUE(reshapeTracker->reshapeCalled()); | |
1894 m_hostImpl->didDrawAllLayers(frame); | |
1895 } | |
1896 | |
1897 class PartialSwapTrackerContext : public FakeWebGraphicsContext3D { | |
1898 public: | |
1899 virtual void postSubBufferCHROMIUM(int x, int y, int width, int height) | |
1900 { | |
1901 m_partialSwapRect = IntRect(x, y, width, height); | |
1902 } | |
1903 | |
1904 virtual WebString getString(WGC3Denum name) | |
1905 { | |
1906 if (name == GraphicsContext3D::EXTENSIONS) | |
1907 return WebString("GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibi
lity"); | |
1908 | |
1909 return WebString(); | |
1910 } | |
1911 | |
1912 IntRect partialSwapRect() const { return m_partialSwapRect; } | |
1913 | |
1914 private: | |
1915 IntRect m_partialSwapRect; | |
1916 }; | |
1917 | |
1918 // Make sure damage tracking propagates all the way to the graphics context, | |
1919 // where it should request to swap only the subBuffer that is damaged. | |
1920 TEST_P(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect) | |
1921 { | |
1922 scoped_ptr<CCGraphicsContext> ccContext = FakeWebCompositorOutputSurface::cr
eate(adoptPtr(new PartialSwapTrackerContext)).PassAs<CCGraphicsContext>(); | |
1923 PartialSwapTrackerContext* partialSwapTracker = static_cast<PartialSwapTrack
erContext*>(ccContext->context3D()); | |
1924 | |
1925 // This test creates its own CCLayerTreeHostImpl, so | |
1926 // that we can force partial swap enabled. | |
1927 CCLayerTreeSettings settings; | |
1928 CCSettings::setPartialSwapEnabled(true); | |
1929 scoped_ptr<CCLayerTreeHostImpl> layerTreeHostImpl = CCLayerTreeHostImpl::cre
ate(settings, this); | |
1930 layerTreeHostImpl->initializeRenderer(ccContext.Pass()); | |
1931 layerTreeHostImpl->setViewportSize(IntSize(500, 500), IntSize(500, 500)); | |
1932 | |
1933 scoped_ptr<CCLayerImpl> root = FakeDrawableCCLayerImpl::create(1); | |
1934 scoped_ptr<CCLayerImpl> child = FakeDrawableCCLayerImpl::create(2); | |
1935 child->setPosition(FloatPoint(12, 13)); | |
1936 child->setAnchorPoint(FloatPoint(0, 0)); | |
1937 child->setBounds(IntSize(14, 15)); | |
1938 child->setContentBounds(IntSize(14, 15)); | |
1939 child->setDrawsContent(true); | |
1940 root->setAnchorPoint(FloatPoint(0, 0)); | |
1941 root->setBounds(IntSize(500, 500)); | |
1942 root->setContentBounds(IntSize(500, 500)); | |
1943 root->setDrawsContent(true); | |
1944 root->addChild(child.Pass()); | |
1945 layerTreeHostImpl->setRootLayer(root.Pass()); | |
1946 | |
1947 CCLayerTreeHostImpl::FrameData frame; | |
1948 | |
1949 // First frame, the entire screen should get swapped. | |
1950 EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame)); | |
1951 layerTreeHostImpl->drawLayers(frame); | |
1952 layerTreeHostImpl->didDrawAllLayers(frame); | |
1953 layerTreeHostImpl->swapBuffers(); | |
1954 IntRect actualSwapRect = partialSwapTracker->partialSwapRect(); | |
1955 IntRect expectedSwapRect = IntRect(IntPoint::zero(), IntSize(500, 500)); | |
1956 EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x()); | |
1957 EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y()); | |
1958 EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width()); | |
1959 EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height()); | |
1960 | |
1961 // Second frame, only the damaged area should get swapped. Damage should be
the union | |
1962 // of old and new child rects. | |
1963 // expected damage rect: IntRect(IntPoint::zero(), IntSize(26, 28)); | |
1964 // expected swap rect: vertically flipped, with origin at bottom left corner
. | |
1965 layerTreeHostImpl->rootLayer()->children()[0]->setPosition(FloatPoint(0, 0))
; | |
1966 EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame)); | |
1967 layerTreeHostImpl->drawLayers(frame); | |
1968 m_hostImpl->didDrawAllLayers(frame); | |
1969 layerTreeHostImpl->swapBuffers(); | |
1970 actualSwapRect = partialSwapTracker->partialSwapRect(); | |
1971 expectedSwapRect = IntRect(IntPoint(0, 500-28), IntSize(26, 28)); | |
1972 EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x()); | |
1973 EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y()); | |
1974 EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width()); | |
1975 EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height()); | |
1976 | |
1977 // Make sure that partial swap is constrained to the viewport dimensions | |
1978 // expected damage rect: IntRect(IntPoint::zero(), IntSize(500, 500)); | |
1979 // expected swap rect: flipped damage rect, but also clamped to viewport | |
1980 layerTreeHostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10)); | |
1981 layerTreeHostImpl->rootLayer()->setOpacity(0.7f); // this will damage everyt
hing | |
1982 EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame)); | |
1983 layerTreeHostImpl->drawLayers(frame); | |
1984 m_hostImpl->didDrawAllLayers(frame); | |
1985 layerTreeHostImpl->swapBuffers(); | |
1986 actualSwapRect = partialSwapTracker->partialSwapRect(); | |
1987 expectedSwapRect = IntRect(IntPoint::zero(), IntSize(10, 10)); | |
1988 EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x()); | |
1989 EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y()); | |
1990 EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width()); | |
1991 EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height()); | |
1992 } | |
1993 | |
1994 TEST_P(CCLayerTreeHostImplTest, rootLayerDoesntCreateExtraSurface) | |
1995 { | |
1996 scoped_ptr<CCLayerImpl> root = FakeDrawableCCLayerImpl::create(1); | |
1997 scoped_ptr<CCLayerImpl> child = FakeDrawableCCLayerImpl::create(2); | |
1998 child->setAnchorPoint(FloatPoint(0, 0)); | |
1999 child->setBounds(IntSize(10, 10)); | |
2000 child->setContentBounds(IntSize(10, 10)); | |
2001 child->setDrawsContent(true); | |
2002 root->setAnchorPoint(FloatPoint(0, 0)); | |
2003 root->setBounds(IntSize(10, 10)); | |
2004 root->setContentBounds(IntSize(10, 10)); | |
2005 root->setDrawsContent(true); | |
2006 root->setOpacity(0.7f); | |
2007 root->addChild(child.Pass()); | |
2008 | |
2009 m_hostImpl->setRootLayer(root.Pass()); | |
2010 | |
2011 CCLayerTreeHostImpl::FrameData frame; | |
2012 | |
2013 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
2014 EXPECT_EQ(1u, frame.renderSurfaceLayerList->size()); | |
2015 EXPECT_EQ(1u, frame.renderPasses.size()); | |
2016 m_hostImpl->didDrawAllLayers(frame); | |
2017 } | |
2018 | |
2019 } // namespace | |
2020 | |
2021 class FakeLayerWithQuads : public CCLayerImpl { | |
2022 public: | |
2023 static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImp
l>(new FakeLayerWithQuads(id)); } | |
2024 | |
2025 virtual void appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuad
sData) OVERRIDE | |
2026 { | |
2027 CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createS
haredQuadState()); | |
2028 | |
2029 SkColor gray = SkColorSetRGB(100, 100, 100); | |
2030 IntRect quadRect(IntPoint(0, 0), contentBounds()); | |
2031 scoped_ptr<CCSolidColorDrawQuad> myQuad = CCSolidColorDrawQuad::create(s
haredQuadState, quadRect, gray); | |
2032 quadSink.append(myQuad.PassAs<CCDrawQuad>(), appendQuadsData); | |
2033 } | |
2034 | |
2035 private: | |
2036 FakeLayerWithQuads(int id) | |
2037 : CCLayerImpl(id) | |
2038 { | |
2039 } | |
2040 }; | |
2041 | |
2042 namespace { | |
2043 | |
2044 class MockContext : public FakeWebGraphicsContext3D { | |
2045 public: | |
2046 MOCK_METHOD1(useProgram, void(WebGLId program)); | |
2047 MOCK_METHOD5(uniform4f, void(WGC3Dint location, WGC3Dfloat x, WGC3Dfloat y,
WGC3Dfloat z, WGC3Dfloat w)); | |
2048 MOCK_METHOD4(uniformMatrix4fv, void(WGC3Dint location, WGC3Dsizei count, WGC
3Dboolean transpose, const WGC3Dfloat* value)); | |
2049 MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum
type, WGC3Dintptr offset)); | |
2050 MOCK_METHOD1(getString, WebString(WGC3Denum name)); | |
2051 MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebString()); | |
2052 MOCK_METHOD1(enable, void(WGC3Denum cap)); | |
2053 MOCK_METHOD1(disable, void(WGC3Denum cap)); | |
2054 MOCK_METHOD4(scissor, void(WGC3Dint x, WGC3Dint y, WGC3Dsizei width, WGC3Dsi
zei height)); | |
2055 }; | |
2056 | |
2057 class MockContextHarness { | |
2058 private: | |
2059 MockContext* m_context; | |
2060 public: | |
2061 MockContextHarness(MockContext* context) | |
2062 : m_context(context) | |
2063 { | |
2064 // Catch "uninteresting" calls | |
2065 EXPECT_CALL(*m_context, useProgram(_)) | |
2066 .Times(0); | |
2067 | |
2068 EXPECT_CALL(*m_context, drawElements(_, _, _, _)) | |
2069 .Times(0); | |
2070 | |
2071 // These are not asserted | |
2072 EXPECT_CALL(*m_context, uniformMatrix4fv(_, _, _, _)) | |
2073 .WillRepeatedly(Return()); | |
2074 | |
2075 EXPECT_CALL(*m_context, uniform4f(_, _, _, _, _)) | |
2076 .WillRepeatedly(Return()); | |
2077 | |
2078 // Any other strings are empty | |
2079 EXPECT_CALL(*m_context, getString(_)) | |
2080 .WillRepeatedly(Return(WebString())); | |
2081 | |
2082 // Support for partial swap, if needed | |
2083 EXPECT_CALL(*m_context, getString(GraphicsContext3D::EXTENSIONS)) | |
2084 .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer"))); | |
2085 | |
2086 EXPECT_CALL(*m_context, getRequestableExtensionsCHROMIUM()) | |
2087 .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer"))); | |
2088 | |
2089 // Any un-sanctioned calls to enable() are OK | |
2090 EXPECT_CALL(*m_context, enable(_)) | |
2091 .WillRepeatedly(Return()); | |
2092 | |
2093 // Any un-sanctioned calls to disable() are OK | |
2094 EXPECT_CALL(*m_context, disable(_)) | |
2095 .WillRepeatedly(Return()); | |
2096 } | |
2097 | |
2098 void mustDrawSolidQuad() | |
2099 { | |
2100 EXPECT_CALL(*m_context, drawElements(GraphicsContext3D::TRIANGLES, 6, Gr
aphicsContext3D::UNSIGNED_SHORT, 0)) | |
2101 .WillOnce(Return()) | |
2102 .RetiresOnSaturation(); | |
2103 | |
2104 // 1 is hardcoded return value of fake createProgram() | |
2105 EXPECT_CALL(*m_context, useProgram(1)) | |
2106 .WillOnce(Return()) | |
2107 .RetiresOnSaturation(); | |
2108 | |
2109 } | |
2110 | |
2111 void mustSetScissor(int x, int y, int width, int height) | |
2112 { | |
2113 EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST)) | |
2114 .WillRepeatedly(Return()); | |
2115 | |
2116 EXPECT_CALL(*m_context, scissor(x, y, width, height)) | |
2117 .Times(AtLeast(1)) | |
2118 .WillRepeatedly(Return()); | |
2119 } | |
2120 | |
2121 void mustSetNoScissor() | |
2122 { | |
2123 EXPECT_CALL(*m_context, disable(GraphicsContext3D::SCISSOR_TEST)) | |
2124 .WillRepeatedly(Return()); | |
2125 | |
2126 EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST)) | |
2127 .Times(0); | |
2128 | |
2129 EXPECT_CALL(*m_context, scissor(_, _, _, _)) | |
2130 .Times(0); | |
2131 } | |
2132 }; | |
2133 | |
2134 TEST_P(CCLayerTreeHostImplTest, noPartialSwap) | |
2135 { | |
2136 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new MockContext)).PassAs<CCGraphicsContext>(); | |
2137 MockContext* mockContext = static_cast<MockContext*>(context->context3D()); | |
2138 MockContextHarness harness(mockContext); | |
2139 | |
2140 harness.mustDrawSolidQuad(); | |
2141 harness.mustSetScissor(0, 0, 10, 10); | |
2142 | |
2143 // Run test case | |
2144 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, cont
ext.Pass(), FakeLayerWithQuads::create(1)); | |
2145 | |
2146 CCLayerTreeHostImpl::FrameData frame; | |
2147 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
2148 myHostImpl->drawLayers(frame); | |
2149 myHostImpl->didDrawAllLayers(frame); | |
2150 Mock::VerifyAndClearExpectations(&mockContext); | |
2151 } | |
2152 | |
2153 TEST_P(CCLayerTreeHostImplTest, partialSwap) | |
2154 { | |
2155 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new MockContext)).PassAs<CCGraphicsContext>(); | |
2156 MockContext* mockContext = static_cast<MockContext*>(context->context3D()); | |
2157 MockContextHarness harness(mockContext); | |
2158 | |
2159 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, conte
xt.Pass(), FakeLayerWithQuads::create(1)); | |
2160 | |
2161 // The first frame is not a partially-swapped one. | |
2162 harness.mustSetScissor(0, 0, 10, 10); | |
2163 harness.mustDrawSolidQuad(); | |
2164 { | |
2165 CCLayerTreeHostImpl::FrameData frame; | |
2166 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
2167 myHostImpl->drawLayers(frame); | |
2168 myHostImpl->didDrawAllLayers(frame); | |
2169 } | |
2170 Mock::VerifyAndClearExpectations(&mockContext); | |
2171 | |
2172 // Damage a portion of the frame. | |
2173 myHostImpl->rootLayer()->setUpdateRect(IntRect(0, 0, 2, 3)); | |
2174 | |
2175 // The second frame will be partially-swapped (the y coordinates are flipped
). | |
2176 harness.mustSetScissor(0, 7, 2, 3); | |
2177 harness.mustDrawSolidQuad(); | |
2178 { | |
2179 CCLayerTreeHostImpl::FrameData frame; | |
2180 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
2181 myHostImpl->drawLayers(frame); | |
2182 myHostImpl->didDrawAllLayers(frame); | |
2183 } | |
2184 Mock::VerifyAndClearExpectations(&mockContext); | |
2185 } | |
2186 | |
2187 class PartialSwapContext : public FakeWebGraphicsContext3D { | |
2188 public: | |
2189 WebString getString(WGC3Denum name) | |
2190 { | |
2191 if (name == GraphicsContext3D::EXTENSIONS) | |
2192 return WebString("GL_CHROMIUM_post_sub_buffer"); | |
2193 return WebString(); | |
2194 } | |
2195 | |
2196 WebString getRequestableExtensionsCHROMIUM() | |
2197 { | |
2198 return WebString("GL_CHROMIUM_post_sub_buffer"); | |
2199 } | |
2200 | |
2201 // Unlimited texture size. | |
2202 virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value) | |
2203 { | |
2204 if (pname == cc::GraphicsContext3D::MAX_TEXTURE_SIZE) | |
2205 *value = 8192; | |
2206 } | |
2207 }; | |
2208 | |
2209 static scoped_ptr<CCLayerTreeHostImpl> setupLayersForOpacity(bool partialSwap, C
CLayerTreeHostImplClient* client) | |
2210 { | |
2211 CCSettings::setPartialSwapEnabled(partialSwap); | |
2212 | |
2213 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); | |
2214 | |
2215 CCLayerTreeSettings settings; | |
2216 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, client); | |
2217 myHostImpl->initializeRenderer(context.Pass()); | |
2218 myHostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100)); | |
2219 | |
2220 /* | |
2221 Layers are created as follows: | |
2222 | |
2223 +--------------------+ | |
2224 | 1 | | |
2225 | +-----------+ | | |
2226 | | 2 | | | |
2227 | | +-------------------+ | |
2228 | | | 3 | | |
2229 | | +-------------------+ | |
2230 | | | | | |
2231 | +-----------+ | | |
2232 | | | |
2233 | | | |
2234 +--------------------+ | |
2235 | |
2236 Layers 1, 2 have render surfaces | |
2237 */ | |
2238 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
2239 scoped_ptr<CCLayerImpl> child = CCLayerImpl::create(2); | |
2240 scoped_ptr<CCLayerImpl> grandChild = FakeLayerWithQuads::create(3); | |
2241 | |
2242 IntRect rootRect(0, 0, 100, 100); | |
2243 IntRect childRect(10, 10, 50, 50); | |
2244 IntRect grandChildRect(5, 5, 150, 150); | |
2245 | |
2246 root->createRenderSurface(); | |
2247 root->setAnchorPoint(FloatPoint(0, 0)); | |
2248 root->setPosition(FloatPoint(rootRect.x(), rootRect.y())); | |
2249 root->setBounds(IntSize(rootRect.width(), rootRect.height())); | |
2250 root->setContentBounds(root->bounds()); | |
2251 root->setVisibleContentRect(rootRect); | |
2252 root->setDrawsContent(false); | |
2253 root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.w
idth(), rootRect.height()))); | |
2254 | |
2255 child->setAnchorPoint(FloatPoint(0, 0)); | |
2256 child->setPosition(FloatPoint(childRect.x(), childRect.y())); | |
2257 child->setOpacity(0.5f); | |
2258 child->setBounds(IntSize(childRect.width(), childRect.height())); | |
2259 child->setContentBounds(child->bounds()); | |
2260 child->setVisibleContentRect(childRect); | |
2261 child->setDrawsContent(false); | |
2262 | |
2263 grandChild->setAnchorPoint(FloatPoint(0, 0)); | |
2264 grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y())); | |
2265 grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height(
))); | |
2266 grandChild->setContentBounds(grandChild->bounds()); | |
2267 grandChild->setVisibleContentRect(grandChildRect); | |
2268 grandChild->setDrawsContent(true); | |
2269 | |
2270 child->addChild(grandChild.Pass()); | |
2271 root->addChild(child.Pass()); | |
2272 | |
2273 myHostImpl->setRootLayer(root.Pass()); | |
2274 return myHostImpl.Pass(); | |
2275 } | |
2276 | |
2277 TEST_P(CCLayerTreeHostImplTest, contributingLayerEmptyScissorPartialSwap) | |
2278 { | |
2279 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(true, thi
s); | |
2280 | |
2281 { | |
2282 CCLayerTreeHostImpl::FrameData frame; | |
2283 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
2284 | |
2285 // Just for consistency, the most interesting stuff already happened | |
2286 myHostImpl->drawLayers(frame); | |
2287 myHostImpl->didDrawAllLayers(frame); | |
2288 | |
2289 // Verify all quads have been computed | |
2290 ASSERT_EQ(2U, frame.renderPasses.size()); | |
2291 ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
2292 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size()); | |
2293 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->
material()); | |
2294 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->
material()); | |
2295 } | |
2296 } | |
2297 | |
2298 TEST_P(CCLayerTreeHostImplTest, contributingLayerEmptyScissorNoPartialSwap) | |
2299 { | |
2300 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(false, th
is); | |
2301 | |
2302 { | |
2303 CCLayerTreeHostImpl::FrameData frame; | |
2304 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
2305 | |
2306 // Just for consistency, the most interesting stuff already happened | |
2307 myHostImpl->drawLayers(frame); | |
2308 myHostImpl->didDrawAllLayers(frame); | |
2309 | |
2310 // Verify all quads have been computed | |
2311 ASSERT_EQ(2U, frame.renderPasses.size()); | |
2312 ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
2313 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size()); | |
2314 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->
material()); | |
2315 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->
material()); | |
2316 } | |
2317 } | |
2318 | |
2319 // Make sure that context lost notifications are propagated through the tree. | |
2320 class ContextLostNotificationCheckLayer : public CCLayerImpl { | |
2321 public: | |
2322 static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImp
l>(new ContextLostNotificationCheckLayer(id)); } | |
2323 | |
2324 virtual void didLoseContext() OVERRIDE | |
2325 { | |
2326 m_didLoseContextCalled = true; | |
2327 } | |
2328 | |
2329 bool didLoseContextCalled() const { return m_didLoseContextCalled; } | |
2330 | |
2331 private: | |
2332 explicit ContextLostNotificationCheckLayer(int id) | |
2333 : CCLayerImpl(id) | |
2334 , m_didLoseContextCalled(false) | |
2335 { | |
2336 } | |
2337 | |
2338 bool m_didLoseContextCalled; | |
2339 }; | |
2340 | |
2341 TEST_P(CCLayerTreeHostImplTest, contextLostAndRestoredNotificationSentToAllLayer
s) | |
2342 { | |
2343 m_hostImpl->setRootLayer(ContextLostNotificationCheckLayer::create(1)); | |
2344 ContextLostNotificationCheckLayer* root = static_cast<ContextLostNotificatio
nCheckLayer*>(m_hostImpl->rootLayer()); | |
2345 | |
2346 root->addChild(ContextLostNotificationCheckLayer::create(1)); | |
2347 ContextLostNotificationCheckLayer* layer1 = static_cast<ContextLostNotificat
ionCheckLayer*>(root->children()[0]); | |
2348 | |
2349 layer1->addChild(ContextLostNotificationCheckLayer::create(2)); | |
2350 ContextLostNotificationCheckLayer* layer2 = static_cast<ContextLostNotificat
ionCheckLayer*>(layer1->children()[0]); | |
2351 | |
2352 EXPECT_FALSE(root->didLoseContextCalled()); | |
2353 EXPECT_FALSE(layer1->didLoseContextCalled()); | |
2354 EXPECT_FALSE(layer2->didLoseContextCalled()); | |
2355 | |
2356 m_hostImpl->initializeRenderer(createContext()); | |
2357 | |
2358 EXPECT_TRUE(root->didLoseContextCalled()); | |
2359 EXPECT_TRUE(layer1->didLoseContextCalled()); | |
2360 EXPECT_TRUE(layer2->didLoseContextCalled()); | |
2361 } | |
2362 | |
2363 TEST_P(CCLayerTreeHostImplTest, finishAllRenderingAfterContextLost) | |
2364 { | |
2365 CCLayerTreeSettings settings; | |
2366 m_hostImpl = CCLayerTreeHostImpl::create(settings, this); | |
2367 | |
2368 // The context initialization will fail, but we should still be able to call
finishAllRendering() without any ill effects. | |
2369 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptP
tr(new FakeWebGraphicsContext3DMakeCurrentFails)).PassAs<CCGraphicsContext>()); | |
2370 m_hostImpl->finishAllRendering(); | |
2371 } | |
2372 | |
2373 class FakeWebGraphicsContext3DMakeCurrentFailsEventually : public FakeWebGraphic
sContext3D { | |
2374 public: | |
2375 explicit FakeWebGraphicsContext3DMakeCurrentFailsEventually(unsigned succeed
Count) : m_succeedCount(succeedCount) { } | |
2376 virtual bool makeContextCurrent() { | |
2377 if (!m_succeedCount) | |
2378 return false; | |
2379 --m_succeedCount; | |
2380 return true; | |
2381 } | |
2382 | |
2383 private: | |
2384 unsigned m_succeedCount; | |
2385 }; | |
2386 | |
2387 TEST_P(CCLayerTreeHostImplTest, contextLostDuringInitialize) | |
2388 { | |
2389 CCLayerTreeSettings settings; | |
2390 m_hostImpl = CCLayerTreeHostImpl::create(settings, this); | |
2391 | |
2392 // Initialize into a known successful state. | |
2393 EXPECT_TRUE(m_hostImpl->initializeRenderer(createContext())); | |
2394 EXPECT_TRUE(m_hostImpl->context()); | |
2395 EXPECT_TRUE(m_hostImpl->renderer()); | |
2396 EXPECT_TRUE(m_hostImpl->resourceProvider()); | |
2397 | |
2398 // We will make the context get lost after a numer of makeContextCurrent | |
2399 // calls. The exact number of calls to make it succeed is dependent on the | |
2400 // implementation and doesn't really matter (i.e. can be changed to make the | |
2401 // tests pass after some refactoring). | |
2402 const unsigned kMakeCurrentSuccessesNeededForSuccessfulInitialization = 3; | |
2403 | |
2404 for (unsigned i = 0; i < kMakeCurrentSuccessesNeededForSuccessfulInitializat
ion; ++i) { | |
2405 // The context will get lost during initialization, we shouldn't crash.
We | |
2406 // should also be in a consistent state. | |
2407 EXPECT_FALSE(m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurfa
ce::create(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFailsEventually(i))).
PassAs<CCGraphicsContext>())); | |
2408 EXPECT_EQ(0, m_hostImpl->context()); | |
2409 EXPECT_EQ(0, m_hostImpl->renderer()); | |
2410 EXPECT_EQ(0, m_hostImpl->resourceProvider()); | |
2411 EXPECT_TRUE(m_hostImpl->initializeRenderer(createContext())); | |
2412 } | |
2413 | |
2414 EXPECT_TRUE(m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::c
reate(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFailsEventually(kMakeCurre
ntSuccessesNeededForSuccessfulInitialization))).PassAs<CCGraphicsContext>())); | |
2415 EXPECT_TRUE(m_hostImpl->context()); | |
2416 EXPECT_TRUE(m_hostImpl->renderer()); | |
2417 EXPECT_TRUE(m_hostImpl->resourceProvider()); | |
2418 } | |
2419 | |
2420 // Fake WebGraphicsContext3D that will cause a failure if trying to use a | |
2421 // resource that wasn't created by it (resources created by | |
2422 // FakeWebGraphicsContext3D have an id of 1). | |
2423 class StrictWebGraphicsContext3D : public FakeWebGraphicsContext3D { | |
2424 public: | |
2425 StrictWebGraphicsContext3D() | |
2426 : FakeWebGraphicsContext3D() | |
2427 { | |
2428 m_nextTextureId = 7; // Start allocating texture ids larger than any oth
er resource IDs so we can tell if someone's mixing up their resource types. | |
2429 } | |
2430 | |
2431 virtual WebGLId createBuffer() { return 2; } | |
2432 virtual WebGLId createFramebuffer() { return 3; } | |
2433 virtual WebGLId createProgram() { return 4; } | |
2434 virtual WebGLId createRenderbuffer() { return 5; } | |
2435 virtual WebGLId createShader(WGC3Denum) { return 6; } | |
2436 | |
2437 virtual void deleteBuffer(WebGLId id) | |
2438 { | |
2439 if (id != 2) | |
2440 ADD_FAILURE() << "Trying to delete buffer id " << id; | |
2441 } | |
2442 | |
2443 virtual void deleteFramebuffer(WebGLId id) | |
2444 { | |
2445 if (id != 3) | |
2446 ADD_FAILURE() << "Trying to delete framebuffer id " << id; | |
2447 } | |
2448 | |
2449 virtual void deleteProgram(WebGLId id) | |
2450 { | |
2451 if (id != 4) | |
2452 ADD_FAILURE() << "Trying to delete program id " << id; | |
2453 } | |
2454 | |
2455 virtual void deleteRenderbuffer(WebGLId id) | |
2456 { | |
2457 if (id != 5) | |
2458 ADD_FAILURE() << "Trying to delete renderbuffer id " << id; | |
2459 } | |
2460 | |
2461 virtual void deleteShader(WebGLId id) | |
2462 { | |
2463 if (id != 6) | |
2464 ADD_FAILURE() << "Trying to delete shader id " << id; | |
2465 } | |
2466 | |
2467 virtual WebGLId createTexture() | |
2468 { | |
2469 unsigned textureId = FakeWebGraphicsContext3D::createTexture(); | |
2470 m_allocatedTextureIds.insert(textureId); | |
2471 return textureId; | |
2472 } | |
2473 virtual void deleteTexture(WebGLId id) | |
2474 { | |
2475 if (!ContainsKey(m_allocatedTextureIds, id)) | |
2476 ADD_FAILURE() << "Trying to delete texture id " << id; | |
2477 m_allocatedTextureIds.erase(id); | |
2478 } | |
2479 | |
2480 virtual void bindBuffer(WGC3Denum, WebGLId id) | |
2481 { | |
2482 if (id != 2 && id) | |
2483 ADD_FAILURE() << "Trying to bind buffer id " << id; | |
2484 } | |
2485 | |
2486 virtual void bindFramebuffer(WGC3Denum, WebGLId id) | |
2487 { | |
2488 if (id != 3 && id) | |
2489 ADD_FAILURE() << "Trying to bind framebuffer id " << id; | |
2490 } | |
2491 | |
2492 virtual void useProgram(WebGLId id) | |
2493 { | |
2494 if (id != 4) | |
2495 ADD_FAILURE() << "Trying to use program id " << id; | |
2496 } | |
2497 | |
2498 virtual void bindRenderbuffer(WGC3Denum, WebGLId id) | |
2499 { | |
2500 if (id != 5 && id) | |
2501 ADD_FAILURE() << "Trying to bind renderbuffer id " << id; | |
2502 } | |
2503 | |
2504 virtual void attachShader(WebGLId program, WebGLId shader) | |
2505 { | |
2506 if ((program != 4) || (shader != 6)) | |
2507 ADD_FAILURE() << "Trying to attach shader id " << shader << " to pro
gram id " << program; | |
2508 } | |
2509 | |
2510 virtual void bindTexture(WGC3Denum, WebGLId id) | |
2511 { | |
2512 if (id && !ContainsKey(m_allocatedTextureIds, id)) | |
2513 ADD_FAILURE() << "Trying to bind texture id " << id; | |
2514 } | |
2515 | |
2516 private: | |
2517 base::hash_set<unsigned> m_allocatedTextureIds; | |
2518 }; | |
2519 | |
2520 // Fake video frame that represents a 4x4 YUV video frame. | |
2521 class FakeVideoFrame: public WebVideoFrame { | |
2522 public: | |
2523 FakeVideoFrame() : m_textureId(0) { memset(m_data, 0x80, sizeof(m_data)); } | |
2524 virtual ~FakeVideoFrame() { } | |
2525 virtual Format format() const { return m_textureId ? FormatNativeTexture : F
ormatYV12; } | |
2526 virtual unsigned width() const { return 4; } | |
2527 virtual unsigned height() const { return 4; } | |
2528 virtual unsigned planes() const { return 3; } | |
2529 virtual int stride(unsigned plane) const { return 4; } | |
2530 virtual const void* data(unsigned plane) const { return m_data; } | |
2531 virtual unsigned textureId() const { return m_textureId; } | |
2532 virtual unsigned textureTarget() const { return m_textureId ? GraphicsContex
t3D::TEXTURE_2D : 0; } | |
2533 | |
2534 void setTextureId(unsigned id) { m_textureId = id; } | |
2535 | |
2536 private: | |
2537 char m_data[16]; | |
2538 unsigned m_textureId; | |
2539 }; | |
2540 | |
2541 // Fake video frame provider that always provides the same FakeVideoFrame. | |
2542 class FakeVideoFrameProvider: public WebVideoFrameProvider { | |
2543 public: | |
2544 FakeVideoFrameProvider() : m_frame(0), m_client(0) { } | |
2545 virtual ~FakeVideoFrameProvider() | |
2546 { | |
2547 if (m_client) | |
2548 m_client->stopUsingProvider(); | |
2549 } | |
2550 | |
2551 virtual void setVideoFrameProviderClient(Client* client) { m_client = client
; } | |
2552 virtual WebVideoFrame* getCurrentFrame() { return m_frame; } | |
2553 virtual void putCurrentFrame(WebVideoFrame*) { } | |
2554 | |
2555 void setFrame(WebVideoFrame* frame) { m_frame = frame; } | |
2556 | |
2557 private: | |
2558 WebVideoFrame* m_frame; | |
2559 Client* m_client; | |
2560 }; | |
2561 | |
2562 class StrictWebGraphicsContext3DWithIOSurface : public StrictWebGraphicsContext3
D { | |
2563 public: | |
2564 virtual WebString getString(WGC3Denum name) OVERRIDE | |
2565 { | |
2566 if (name == cc::GraphicsContext3D::EXTENSIONS) | |
2567 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle"); | |
2568 | |
2569 return WebString(); | |
2570 } | |
2571 }; | |
2572 | |
2573 class FakeWebGraphicsContext3DWithIOSurface : public FakeWebGraphicsContext3D { | |
2574 public: | |
2575 virtual WebString getString(WGC3Denum name) OVERRIDE | |
2576 { | |
2577 if (name == cc::GraphicsContext3D::EXTENSIONS) | |
2578 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle"); | |
2579 | |
2580 return WebString(); | |
2581 } | |
2582 }; | |
2583 | |
2584 class FakeWebScrollbarThemeGeometryNonEmpty : public FakeWebScrollbarThemeGeomet
ry { | |
2585 virtual WebRect trackRect(WebScrollbar*) OVERRIDE { return WebRect(0, 0, 10,
10); } | |
2586 virtual WebRect thumbRect(WebScrollbar*) OVERRIDE { return WebRect(0, 5, 5,
2); } | |
2587 virtual void splitTrack(WebScrollbar*, const WebRect& track, WebRect& startT
rack, WebRect& thumb, WebRect& endTrack) OVERRIDE | |
2588 { | |
2589 thumb = WebRect(0, 5, 5, 2); | |
2590 startTrack = WebRect(0, 5, 0, 5); | |
2591 endTrack = WebRect(0, 0, 0, 5); | |
2592 } | |
2593 }; | |
2594 | |
2595 class FakeScrollbarLayerImpl : public CCScrollbarLayerImpl { | |
2596 public: | |
2597 static scoped_ptr<FakeScrollbarLayerImpl> create(int id) | |
2598 { | |
2599 return make_scoped_ptr(new FakeScrollbarLayerImpl(id)); | |
2600 } | |
2601 | |
2602 void createResources(CCResourceProvider* provider) | |
2603 { | |
2604 ASSERT(provider); | |
2605 int pool = 0; | |
2606 IntSize size(10, 10); | |
2607 GC3Denum format = GraphicsContext3D::RGBA; | |
2608 CCResourceProvider::TextureUsageHint hint = CCResourceProvider::TextureU
sageAny; | |
2609 setScrollbarGeometry(CCScrollbarGeometryFixedThumb::create(FakeWebScroll
barThemeGeometryNonEmpty::create())); | |
2610 | |
2611 setBackTrackResourceId(provider->createResource(pool, size, format, hint
)); | |
2612 setForeTrackResourceId(provider->createResource(pool, size, format, hint
)); | |
2613 setThumbResourceId(provider->createResource(pool, size, format, hint)); | |
2614 } | |
2615 | |
2616 protected: | |
2617 explicit FakeScrollbarLayerImpl(int id) | |
2618 : CCScrollbarLayerImpl(id) | |
2619 { | |
2620 } | |
2621 }; | |
2622 | |
2623 static inline scoped_ptr<CCRenderPass> createRenderPassWithResource(CCResourcePr
ovider* provider) | |
2624 { | |
2625 CCResourceProvider::ResourceId resourceId = provider->createResource(0, IntS
ize(1, 1), GraphicsContext3D::RGBA, CCResourceProvider::TextureUsageAny); | |
2626 | |
2627 scoped_ptr<CCRenderPass> pass = CCRenderPass::create(CCRenderPass::Id(1, 1),
IntRect(0, 0, 1, 1), WebTransformationMatrix()); | |
2628 scoped_ptr<CCSharedQuadState> sharedState = CCSharedQuadState::create(WebTra
nsformationMatrix(), IntRect(0, 0, 1, 1), IntRect(0, 0, 1, 1), 1, false); | |
2629 scoped_ptr<CCTextureDrawQuad> quad = CCTextureDrawQuad::create(sharedState.g
et(), IntRect(0, 0, 1, 1), resourceId, false, FloatRect(0, 0, 1, 1), false); | |
2630 | |
2631 static_cast<CCTestRenderPass*>(pass.get())->appendSharedQuadState(sharedStat
e.Pass()); | |
2632 static_cast<CCTestRenderPass*>(pass.get())->appendQuad(quad.PassAs<CCDrawQua
d>()); | |
2633 | |
2634 return pass.Pass(); | |
2635 } | |
2636 | |
2637 TEST_P(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext) | |
2638 { | |
2639 int layerId = 1; | |
2640 | |
2641 scoped_ptr<CCLayerImpl> rootLayer(CCLayerImpl::create(layerId++)); | |
2642 rootLayer->setBounds(IntSize(10, 10)); | |
2643 rootLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2644 | |
2645 scoped_ptr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(layerId++)
; | |
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, 1
0), 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.PassAs<CCLayerImpl>()); | |
2656 | |
2657 scoped_ptr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(lay
erId++); | |
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.PassAs<CCLayerImpl>()); | |
2664 | |
2665 scoped_ptr<CCTiledLayerImpl> maskLayer = CCTiledLayerImpl::create(layerId++)
; | |
2666 maskLayer->setBounds(IntSize(10, 10)); | |
2667 maskLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2668 maskLayer->setContentBounds(IntSize(10, 10)); | |
2669 maskLayer->setDrawsContent(true); | |
2670 maskLayer->setSkipsDraw(false); | |
2671 maskLayer->setTilingData(*tilingData); | |
2672 maskLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10)); | |
2673 | |
2674 scoped_ptr<CCTextureLayerImpl> textureLayerWithMask = CCTextureLayerImpl::cr
eate(layerId++); | |
2675 textureLayerWithMask->setBounds(IntSize(10, 10)); | |
2676 textureLayerWithMask->setAnchorPoint(FloatPoint(0, 0)); | |
2677 textureLayerWithMask->setContentBounds(IntSize(10, 10)); | |
2678 textureLayerWithMask->setDrawsContent(true); | |
2679 textureLayerWithMask->setTextureId(1); | |
2680 textureLayerWithMask->setMaskLayer(maskLayer.PassAs<CCLayerImpl>()); | |
2681 rootLayer->addChild(textureLayerWithMask.PassAs<CCLayerImpl>()); | |
2682 | |
2683 FakeVideoFrame videoFrame; | |
2684 FakeVideoFrameProvider provider; | |
2685 provider.setFrame(&videoFrame); | |
2686 scoped_ptr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(layerId++
, &provider); | |
2687 videoLayer->setBounds(IntSize(10, 10)); | |
2688 videoLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2689 videoLayer->setContentBounds(IntSize(10, 10)); | |
2690 videoLayer->setDrawsContent(true); | |
2691 videoLayer->setLayerTreeHostImpl(m_hostImpl.get()); | |
2692 rootLayer->addChild(videoLayer.PassAs<CCLayerImpl>()); | |
2693 | |
2694 FakeVideoFrame hwVideoFrame; | |
2695 FakeVideoFrameProvider hwProvider; | |
2696 hwProvider.setFrame(&hwVideoFrame); | |
2697 scoped_ptr<CCVideoLayerImpl> hwVideoLayer = CCVideoLayerImpl::create(layerId
++, &hwProvider); | |
2698 hwVideoLayer->setBounds(IntSize(10, 10)); | |
2699 hwVideoLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2700 hwVideoLayer->setContentBounds(IntSize(10, 10)); | |
2701 hwVideoLayer->setDrawsContent(true); | |
2702 hwVideoLayer->setLayerTreeHostImpl(m_hostImpl.get()); | |
2703 rootLayer->addChild(hwVideoLayer.PassAs<CCLayerImpl>()); | |
2704 | |
2705 scoped_ptr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::crea
te(layerId++); | |
2706 ioSurfaceLayer->setBounds(IntSize(10, 10)); | |
2707 ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2708 ioSurfaceLayer->setContentBounds(IntSize(10, 10)); | |
2709 ioSurfaceLayer->setDrawsContent(true); | |
2710 ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10)); | |
2711 ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get()); | |
2712 rootLayer->addChild(ioSurfaceLayer.PassAs<CCLayerImpl>()); | |
2713 | |
2714 scoped_ptr<CCHeadsUpDisplayLayerImpl> hudLayer = CCHeadsUpDisplayLayerImpl::
create(layerId++); | |
2715 hudLayer->setBounds(IntSize(10, 10)); | |
2716 hudLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2717 hudLayer->setContentBounds(IntSize(10, 10)); | |
2718 hudLayer->setDrawsContent(true); | |
2719 hudLayer->setLayerTreeHostImpl(m_hostImpl.get()); | |
2720 rootLayer->addChild(hudLayer.PassAs<CCLayerImpl>()); | |
2721 | |
2722 scoped_ptr<FakeScrollbarLayerImpl> scrollbarLayer(FakeScrollbarLayerImpl::cr
eate(layerId++)); | |
2723 scrollbarLayer->setBounds(IntSize(10, 10)); | |
2724 scrollbarLayer->setContentBounds(IntSize(10, 10)); | |
2725 scrollbarLayer->setDrawsContent(true); | |
2726 scrollbarLayer->setLayerTreeHostImpl(m_hostImpl.get()); | |
2727 scrollbarLayer->createResources(m_hostImpl->resourceProvider()); | |
2728 rootLayer->addChild(scrollbarLayer.PassAs<CCLayerImpl>()); | |
2729 | |
2730 scoped_ptr<CCDelegatedRendererLayerImpl> delegatedRendererLayer(CCDelegatedR
endererLayerImpl::create(layerId++)); | |
2731 delegatedRendererLayer->setBounds(IntSize(10, 10)); | |
2732 delegatedRendererLayer->setContentBounds(IntSize(10, 10)); | |
2733 delegatedRendererLayer->setDrawsContent(true); | |
2734 delegatedRendererLayer->setLayerTreeHostImpl(m_hostImpl.get()); | |
2735 ScopedPtrVector<CCRenderPass> passList; | |
2736 passList.append(createRenderPassWithResource(m_hostImpl->resourceProvider())
); | |
2737 delegatedRendererLayer->setRenderPasses(passList); | |
2738 EXPECT_TRUE(passList.isEmpty()); | |
2739 rootLayer->addChild(delegatedRendererLayer.PassAs<CCLayerImpl>()); | |
2740 | |
2741 // Use a context that supports IOSurfaces | |
2742 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptP
tr(new FakeWebGraphicsContext3DWithIOSurface)).PassAs<CCGraphicsContext>()); | |
2743 | |
2744 hwVideoFrame.setTextureId(m_hostImpl->resourceProvider()->graphicsContext3D(
)->createTexture()); | |
2745 | |
2746 m_hostImpl->setRootLayer(rootLayer.Pass()); | |
2747 | |
2748 CCLayerTreeHostImpl::FrameData frame; | |
2749 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
2750 m_hostImpl->drawLayers(frame); | |
2751 m_hostImpl->didDrawAllLayers(frame); | |
2752 m_hostImpl->swapBuffers(); | |
2753 | |
2754 unsigned numResources = m_hostImpl->resourceProvider()->numResources(); | |
2755 | |
2756 // Lose the context, replacing it with a StrictWebGraphicsContext3DWithIOSur
face, | |
2757 // that will warn if any resource from the previous context gets used. | |
2758 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptP
tr(new StrictWebGraphicsContext3DWithIOSurface)).PassAs<CCGraphicsContext>()); | |
2759 | |
2760 // Create dummy resources so that looking up an old resource will get an | |
2761 // invalid texture id mapping. | |
2762 for (unsigned i = 0; i < numResources; ++i) | |
2763 m_hostImpl->resourceProvider()->createResourceFromExternalTexture(1); | |
2764 | |
2765 // The WebVideoFrameProvider is expected to recreate its textures after a | |
2766 // lost context (or not serve a frame). | |
2767 hwProvider.setFrame(0); | |
2768 | |
2769 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
2770 m_hostImpl->drawLayers(frame); | |
2771 m_hostImpl->didDrawAllLayers(frame); | |
2772 m_hostImpl->swapBuffers(); | |
2773 | |
2774 hwVideoFrame.setTextureId(m_hostImpl->resourceProvider()->graphicsContext3D(
)->createTexture()); | |
2775 hwProvider.setFrame(&hwVideoFrame); | |
2776 | |
2777 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
2778 m_hostImpl->drawLayers(frame); | |
2779 m_hostImpl->didDrawAllLayers(frame); | |
2780 m_hostImpl->swapBuffers(); | |
2781 } | |
2782 | |
2783 // Fake WebGraphicsContext3D that tracks the number of textures in use. | |
2784 class TrackingWebGraphicsContext3D : public FakeWebGraphicsContext3D { | |
2785 public: | |
2786 TrackingWebGraphicsContext3D() | |
2787 : FakeWebGraphicsContext3D() | |
2788 , m_numTextures(0) | |
2789 { } | |
2790 | |
2791 virtual WebGLId createTexture() OVERRIDE | |
2792 { | |
2793 WebGLId id = FakeWebGraphicsContext3D::createTexture(); | |
2794 | |
2795 m_textures.set(id, true); | |
2796 ++m_numTextures; | |
2797 return id; | |
2798 } | |
2799 | |
2800 virtual void deleteTexture(WebGLId id) OVERRIDE | |
2801 { | |
2802 if (!m_textures.get(id)) | |
2803 return; | |
2804 | |
2805 m_textures.set(id, false); | |
2806 --m_numTextures; | |
2807 } | |
2808 | |
2809 virtual WebString getString(WGC3Denum name) OVERRIDE | |
2810 { | |
2811 if (name == cc::GraphicsContext3D::EXTENSIONS) | |
2812 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle"); | |
2813 | |
2814 return WebString(); | |
2815 } | |
2816 | |
2817 unsigned numTextures() const { return m_numTextures; } | |
2818 | |
2819 private: | |
2820 HashMap<WebGLId, bool> m_textures; | |
2821 unsigned m_numTextures; | |
2822 }; | |
2823 | |
2824 TEST_P(CCLayerTreeHostImplTest, layersFreeTextures) | |
2825 { | |
2826 scoped_ptr<CCLayerImpl> rootLayer(CCLayerImpl::create(1)); | |
2827 rootLayer->setBounds(IntSize(10, 10)); | |
2828 rootLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2829 | |
2830 scoped_ptr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(2); | |
2831 tileLayer->setBounds(IntSize(10, 10)); | |
2832 tileLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2833 tileLayer->setContentBounds(IntSize(10, 10)); | |
2834 tileLayer->setDrawsContent(true); | |
2835 tileLayer->setSkipsDraw(false); | |
2836 OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 1
0), CCLayerTilingData::NoBorderTexels)); | |
2837 tilingData->setBounds(IntSize(10, 10)); | |
2838 tileLayer->setTilingData(*tilingData); | |
2839 tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10)); | |
2840 rootLayer->addChild(tileLayer.PassAs<CCLayerImpl>()); | |
2841 | |
2842 scoped_ptr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(3); | |
2843 textureLayer->setBounds(IntSize(10, 10)); | |
2844 textureLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2845 textureLayer->setContentBounds(IntSize(10, 10)); | |
2846 textureLayer->setDrawsContent(true); | |
2847 textureLayer->setTextureId(1); | |
2848 rootLayer->addChild(textureLayer.PassAs<CCLayerImpl>()); | |
2849 | |
2850 FakeVideoFrameProvider provider; | |
2851 scoped_ptr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(4, &provi
der); | |
2852 videoLayer->setBounds(IntSize(10, 10)); | |
2853 videoLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2854 videoLayer->setContentBounds(IntSize(10, 10)); | |
2855 videoLayer->setDrawsContent(true); | |
2856 videoLayer->setLayerTreeHostImpl(m_hostImpl.get()); | |
2857 rootLayer->addChild(videoLayer.PassAs<CCLayerImpl>()); | |
2858 | |
2859 scoped_ptr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::crea
te(5); | |
2860 ioSurfaceLayer->setBounds(IntSize(10, 10)); | |
2861 ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0)); | |
2862 ioSurfaceLayer->setContentBounds(IntSize(10, 10)); | |
2863 ioSurfaceLayer->setDrawsContent(true); | |
2864 ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10)); | |
2865 ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get()); | |
2866 rootLayer->addChild(ioSurfaceLayer.PassAs<CCLayerImpl>()); | |
2867 | |
2868 // Lose the context, replacing it with a TrackingWebGraphicsContext3D (which
the CCLayerTreeHostImpl takes ownership of). | |
2869 scoped_ptr<CCGraphicsContext> ccContext(FakeWebCompositorOutputSurface::crea
te(adoptPtr(new TrackingWebGraphicsContext3D))); | |
2870 TrackingWebGraphicsContext3D* trackingWebGraphicsContext = static_cast<Track
ingWebGraphicsContext3D*>(ccContext->context3D()); | |
2871 m_hostImpl->initializeRenderer(ccContext.Pass()); | |
2872 | |
2873 m_hostImpl->setRootLayer(rootLayer.Pass()); | |
2874 | |
2875 CCLayerTreeHostImpl::FrameData frame; | |
2876 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); | |
2877 m_hostImpl->drawLayers(frame); | |
2878 m_hostImpl->didDrawAllLayers(frame); | |
2879 m_hostImpl->swapBuffers(); | |
2880 | |
2881 EXPECT_GT(trackingWebGraphicsContext->numTextures(), 0u); | |
2882 | |
2883 // Kill the layer tree. | |
2884 m_hostImpl->setRootLayer(CCLayerImpl::create(100)); | |
2885 // There should be no textures left in use after. | |
2886 EXPECT_EQ(0u, trackingWebGraphicsContext->numTextures()); | |
2887 } | |
2888 | |
2889 class MockDrawQuadsToFillScreenContext : public FakeWebGraphicsContext3D { | |
2890 public: | |
2891 MOCK_METHOD1(useProgram, void(WebGLId program)); | |
2892 MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum
type, WGC3Dintptr offset)); | |
2893 }; | |
2894 | |
2895 TEST_P(CCLayerTreeHostImplTest, hasTransparentBackground) | |
2896 { | |
2897 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new MockDrawQuadsToFillScreenContext)).PassAs<CCGraphicsContext>(); | |
2898 MockDrawQuadsToFillScreenContext* mockContext = static_cast<MockDrawQuadsToF
illScreenContext*>(context->context3D()); | |
2899 | |
2900 // Run test case | |
2901 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, cont
ext.Pass(), CCLayerImpl::create(1)); | |
2902 myHostImpl->setBackgroundColor(SK_ColorWHITE); | |
2903 | |
2904 // Verify one quad is drawn when transparent background set is not set. | |
2905 myHostImpl->setHasTransparentBackground(false); | |
2906 EXPECT_CALL(*mockContext, useProgram(_)) | |
2907 .Times(1); | |
2908 EXPECT_CALL(*mockContext, drawElements(_, _, _, _)) | |
2909 .Times(1); | |
2910 CCLayerTreeHostImpl::FrameData frame; | |
2911 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
2912 myHostImpl->drawLayers(frame); | |
2913 myHostImpl->didDrawAllLayers(frame); | |
2914 Mock::VerifyAndClearExpectations(&mockContext); | |
2915 | |
2916 // Verify no quads are drawn when transparent background is set. | |
2917 myHostImpl->setHasTransparentBackground(true); | |
2918 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
2919 myHostImpl->drawLayers(frame); | |
2920 myHostImpl->didDrawAllLayers(frame); | |
2921 Mock::VerifyAndClearExpectations(&mockContext); | |
2922 } | |
2923 | |
2924 static void addDrawingLayerTo(CCLayerImpl* parent, int id, const IntRect& layerR
ect, CCLayerImpl** result) | |
2925 { | |
2926 scoped_ptr<CCLayerImpl> layer = FakeLayerWithQuads::create(id); | |
2927 CCLayerImpl* layerPtr = layer.get(); | |
2928 layerPtr->setAnchorPoint(FloatPoint(0, 0)); | |
2929 layerPtr->setPosition(FloatPoint(layerRect.location())); | |
2930 layerPtr->setBounds(layerRect.size()); | |
2931 layerPtr->setContentBounds(layerRect.size()); | |
2932 layerPtr->setDrawsContent(true); // only children draw content | |
2933 layerPtr->setContentsOpaque(true); | |
2934 parent->addChild(layer.Pass()); | |
2935 if (result) | |
2936 *result = layerPtr; | |
2937 } | |
2938 | |
2939 static void setupLayersForTextureCaching(CCLayerTreeHostImpl* layerTreeHostImpl,
CCLayerImpl*& rootPtr, CCLayerImpl*& intermediateLayerPtr, CCLayerImpl*& surfac
eLayerPtr, CCLayerImpl*& childPtr, const IntSize& rootSize) | |
2940 { | |
2941 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); | |
2942 | |
2943 layerTreeHostImpl->initializeRenderer(context.Pass()); | |
2944 layerTreeHostImpl->setViewportSize(rootSize, rootSize); | |
2945 | |
2946 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
2947 rootPtr = root.get(); | |
2948 | |
2949 root->setAnchorPoint(FloatPoint(0, 0)); | |
2950 root->setPosition(FloatPoint(0, 0)); | |
2951 root->setBounds(rootSize); | |
2952 root->setContentBounds(rootSize); | |
2953 root->setDrawsContent(true); | |
2954 layerTreeHostImpl->setRootLayer(root.Pass()); | |
2955 | |
2956 addDrawingLayerTo(rootPtr, 2, IntRect(10, 10, rootSize.width(), rootSize.hei
ght()), &intermediateLayerPtr); | |
2957 intermediateLayerPtr->setDrawsContent(false); // only children draw content | |
2958 | |
2959 // Surface layer is the layer that changes its opacity | |
2960 // It will contain other layers that draw content. | |
2961 addDrawingLayerTo(intermediateLayerPtr, 3, IntRect(10, 10, rootSize.width(),
rootSize.height()), &surfaceLayerPtr); | |
2962 surfaceLayerPtr->setDrawsContent(false); // only children draw content | |
2963 surfaceLayerPtr->setOpacity(0.5f); // This will cause it to have a surface | |
2964 | |
2965 // Child of the surface layer will produce some quads | |
2966 addDrawingLayerTo(surfaceLayerPtr, 4, IntRect(5, 5, rootSize.width() - 25, r
ootSize.height() - 25), &childPtr); | |
2967 } | |
2968 | |
2969 class CCRendererGLWithReleaseTextures : public CCRendererGL { | |
2970 public: | |
2971 using CCRendererGL::releaseRenderPassTextures; | |
2972 }; | |
2973 | |
2974 TEST_P(CCLayerTreeHostImplTest, textureCachingWithClipping) | |
2975 { | |
2976 CCSettings::setPartialSwapEnabled(true); | |
2977 | |
2978 CCLayerTreeSettings settings; | |
2979 settings.minimumOcclusionTrackingSize = IntSize(); | |
2980 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, this); | |
2981 | |
2982 CCLayerImpl* rootPtr; | |
2983 CCLayerImpl* surfaceLayerPtr; | |
2984 | |
2985 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); | |
2986 | |
2987 IntSize rootSize(100, 100); | |
2988 | |
2989 myHostImpl->initializeRenderer(context.Pass()); | |
2990 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In
tSize(rootSize.width(), rootSize.height())); | |
2991 | |
2992 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
2993 rootPtr = root.get(); | |
2994 | |
2995 root->setAnchorPoint(FloatPoint(0, 0)); | |
2996 root->setPosition(FloatPoint(0, 0)); | |
2997 root->setBounds(rootSize); | |
2998 root->setContentBounds(rootSize); | |
2999 root->setDrawsContent(true); | |
3000 root->setMasksToBounds(true); | |
3001 myHostImpl->setRootLayer(root.Pass()); | |
3002 | |
3003 addDrawingLayerTo(rootPtr, 3, IntRect(0, 0, rootSize.width(), rootSize.heigh
t()), &surfaceLayerPtr); | |
3004 surfaceLayerPtr->setDrawsContent(false); | |
3005 | |
3006 // Surface layer is the layer that changes its opacity | |
3007 // It will contain other layers that draw content. | |
3008 surfaceLayerPtr->setOpacity(0.5f); // This will cause it to have a surface | |
3009 | |
3010 addDrawingLayerTo(surfaceLayerPtr, 4, IntRect(0, 0, 100, 3), 0); | |
3011 addDrawingLayerTo(surfaceLayerPtr, 5, IntRect(0, 97, 100, 3), 0); | |
3012 | |
3013 // Rotation will put part of the child ouside the bounds of the root layer. | |
3014 // Nevertheless, the child layers should be drawn. | |
3015 WebTransformationMatrix transform = surfaceLayerPtr->transform(); | |
3016 transform.translate(50, 50); | |
3017 transform.rotate(35); | |
3018 transform.translate(-50, -50); | |
3019 surfaceLayerPtr->setTransform(transform); | |
3020 | |
3021 { | |
3022 CCLayerTreeHostImpl::FrameData frame; | |
3023 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3024 | |
3025 // Must receive two render passes, each with one quad | |
3026 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3027 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); | |
3028 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size()); | |
3029 | |
3030 // Verify that the child layers are being clipped. | |
3031 IntRect quadVisibleRect = frame.renderPasses[0]->quadList()[0]->quadVisi
bleRect(); | |
3032 EXPECT_LT(quadVisibleRect.width(), 100); | |
3033 | |
3034 quadVisibleRect = frame.renderPasses[0]->quadList()[1]->quadVisibleRect(
); | |
3035 EXPECT_LT(quadVisibleRect.width(), 100); | |
3036 | |
3037 // Verify that the render surface texture is *not* clipped. | |
3038 EXPECT_RECT_EQ(IntRect(0, 0, 100, 100), frame.renderPasses[0]->outputRec
t()); | |
3039 | |
3040 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->
material()); | |
3041 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[1]->quadList()[0]); | |
3042 EXPECT_FALSE(quad->contentsChangedSinceLastFrame().isEmpty()); | |
3043 | |
3044 myHostImpl->drawLayers(frame); | |
3045 myHostImpl->didDrawAllLayers(frame); | |
3046 } | |
3047 | |
3048 transform = surfaceLayerPtr->transform(); | |
3049 transform.translate(50, 50); | |
3050 transform.rotate(-35); | |
3051 transform.translate(-50, -50); | |
3052 surfaceLayerPtr->setTransform(transform); | |
3053 | |
3054 // The surface is now aligned again, and the clipped parts are exposed. | |
3055 // Since the layers were clipped, even though the render surface size | |
3056 // was not changed, the texture should not be saved. | |
3057 { | |
3058 CCLayerTreeHostImpl::FrameData frame; | |
3059 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3060 | |
3061 // Must receive two render passes, each with one quad | |
3062 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3063 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); | |
3064 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size()); | |
3065 | |
3066 myHostImpl->drawLayers(frame); | |
3067 myHostImpl->didDrawAllLayers(frame); | |
3068 } | |
3069 } | |
3070 | |
3071 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusion) | |
3072 { | |
3073 CCSettings::setPartialSwapEnabled(false); | |
3074 | |
3075 CCLayerTreeSettings settings; | |
3076 settings.minimumOcclusionTrackingSize = IntSize(); | |
3077 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, this); | |
3078 | |
3079 // Layers are structure as follows: | |
3080 // | |
3081 // R +-- S1 +- L10 (owning) | |
3082 // | +- L11 | |
3083 // | +- L12 | |
3084 // | | |
3085 // +-- S2 +- L20 (owning) | |
3086 // +- L21 | |
3087 // | |
3088 // Occlusion: | |
3089 // L12 occludes L11 (internal) | |
3090 // L20 occludes L10 (external) | |
3091 // L21 occludes L20 (internal) | |
3092 | |
3093 CCLayerImpl* rootPtr; | |
3094 CCLayerImpl* layerS1Ptr; | |
3095 CCLayerImpl* layerS2Ptr; | |
3096 | |
3097 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); | |
3098 | |
3099 IntSize rootSize(1000, 1000); | |
3100 | |
3101 myHostImpl->initializeRenderer(context.Pass()); | |
3102 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In
tSize(rootSize.width(), rootSize.height())); | |
3103 | |
3104 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
3105 rootPtr = root.get(); | |
3106 | |
3107 root->setAnchorPoint(FloatPoint(0, 0)); | |
3108 root->setPosition(FloatPoint(0, 0)); | |
3109 root->setBounds(rootSize); | |
3110 root->setContentBounds(rootSize); | |
3111 root->setDrawsContent(true); | |
3112 root->setMasksToBounds(true); | |
3113 myHostImpl->setRootLayer(root.Pass()); | |
3114 | |
3115 addDrawingLayerTo(rootPtr, 2, IntRect(300, 300, 300, 300), &layerS1Ptr); | |
3116 layerS1Ptr->setForceRenderSurface(true); | |
3117 | |
3118 addDrawingLayerTo(layerS1Ptr, 3, IntRect(10, 10, 10, 10), 0); // L11 | |
3119 addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 0, 30, 30), 0); // L12 | |
3120 | |
3121 addDrawingLayerTo(rootPtr, 5, IntRect(550, 250, 300, 400), &layerS2Ptr); | |
3122 layerS2Ptr->setForceRenderSurface(true); | |
3123 | |
3124 addDrawingLayerTo(layerS2Ptr, 6, IntRect(20, 20, 5, 5), 0); // L21 | |
3125 | |
3126 // Initial draw - must receive all quads | |
3127 { | |
3128 CCLayerTreeHostImpl::FrameData frame; | |
3129 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3130 | |
3131 // Must receive 3 render passes. | |
3132 // For Root, there are 2 quads; for S1, there are 2 quads (1 is occluded
); for S2, there is 2 quads. | |
3133 ASSERT_EQ(3U, frame.renderPasses.size()); | |
3134 | |
3135 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); | |
3136 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); | |
3137 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size()); | |
3138 | |
3139 myHostImpl->drawLayers(frame); | |
3140 myHostImpl->didDrawAllLayers(frame); | |
3141 } | |
3142 | |
3143 // "Unocclude" surface S1 and repeat draw. | |
3144 // Must remove S2's render pass since it's cached; | |
3145 // Must keep S1 quads because texture contained external occlusion. | |
3146 WebTransformationMatrix transform = layerS2Ptr->transform(); | |
3147 transform.translate(150, 150); | |
3148 layerS2Ptr->setTransform(transform); | |
3149 { | |
3150 CCLayerTreeHostImpl::FrameData frame; | |
3151 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3152 | |
3153 // Must receive 2 render passes. | |
3154 // For Root, there are 2 quads | |
3155 // For S1, the number of quads depends on what got unoccluded, so not as
serted beyond being positive. | |
3156 // For S2, there is no render pass | |
3157 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3158 | |
3159 EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U); | |
3160 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); | |
3161 | |
3162 myHostImpl->drawLayers(frame); | |
3163 myHostImpl->didDrawAllLayers(frame); | |
3164 } | |
3165 | |
3166 // "Re-occlude" surface S1 and repeat draw. | |
3167 // Must remove S1's render pass since it is now available in full. | |
3168 // S2 has no change so must also be removed. | |
3169 transform = layerS2Ptr->transform(); | |
3170 transform.translate(-15, -15); | |
3171 layerS2Ptr->setTransform(transform); | |
3172 { | |
3173 CCLayerTreeHostImpl::FrameData frame; | |
3174 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3175 | |
3176 // Must receive 1 render pass - for the root. | |
3177 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3178 | |
3179 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); | |
3180 | |
3181 myHostImpl->drawLayers(frame); | |
3182 myHostImpl->didDrawAllLayers(frame); | |
3183 } | |
3184 | |
3185 } | |
3186 | |
3187 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionEarlyOut) | |
3188 { | |
3189 CCSettings::setPartialSwapEnabled(false); | |
3190 | |
3191 CCLayerTreeSettings settings; | |
3192 settings.minimumOcclusionTrackingSize = IntSize(); | |
3193 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, this); | |
3194 | |
3195 // Layers are structure as follows: | |
3196 // | |
3197 // R +-- S1 +- L10 (owning, non drawing) | |
3198 // | +- L11 (corner, unoccluded) | |
3199 // | +- L12 (corner, unoccluded) | |
3200 // | +- L13 (corner, unoccluded) | |
3201 // | +- L14 (corner, entirely occluded) | |
3202 // | | |
3203 // +-- S2 +- L20 (owning, drawing) | |
3204 // | |
3205 | |
3206 CCLayerImpl* rootPtr; | |
3207 CCLayerImpl* layerS1Ptr; | |
3208 CCLayerImpl* layerS2Ptr; | |
3209 | |
3210 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); | |
3211 | |
3212 IntSize rootSize(1000, 1000); | |
3213 | |
3214 myHostImpl->initializeRenderer(context.Pass()); | |
3215 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In
tSize(rootSize.width(), rootSize.height())); | |
3216 | |
3217 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
3218 rootPtr = root.get(); | |
3219 | |
3220 root->setAnchorPoint(FloatPoint(0, 0)); | |
3221 root->setPosition(FloatPoint(0, 0)); | |
3222 root->setBounds(rootSize); | |
3223 root->setContentBounds(rootSize); | |
3224 root->setDrawsContent(true); | |
3225 root->setMasksToBounds(true); | |
3226 myHostImpl->setRootLayer(root.Pass()); | |
3227 | |
3228 addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 800, 800), &layerS1Ptr); | |
3229 layerS1Ptr->setForceRenderSurface(true); | |
3230 layerS1Ptr->setDrawsContent(false); | |
3231 | |
3232 addDrawingLayerTo(layerS1Ptr, 3, IntRect(0, 0, 300, 300), 0); // L11 | |
3233 addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 500, 300, 300), 0); // L12 | |
3234 addDrawingLayerTo(layerS1Ptr, 5, IntRect(500, 0, 300, 300), 0); // L13 | |
3235 addDrawingLayerTo(layerS1Ptr, 6, IntRect(500, 500, 300, 300), 0); // L14 | |
3236 addDrawingLayerTo(layerS1Ptr, 9, IntRect(500, 500, 300, 300), 0); // L14 | |
3237 | |
3238 addDrawingLayerTo(rootPtr, 7, IntRect(450, 450, 450, 450), &layerS2Ptr); | |
3239 layerS2Ptr->setForceRenderSurface(true); | |
3240 | |
3241 // Initial draw - must receive all quads | |
3242 { | |
3243 CCLayerTreeHostImpl::FrameData frame; | |
3244 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3245 | |
3246 // Must receive 3 render passes. | |
3247 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there
is 1 quad. | |
3248 ASSERT_EQ(3U, frame.renderPasses.size()); | |
3249 | |
3250 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3251 | |
3252 // L14 is culled, so only 3 quads. | |
3253 EXPECT_EQ(3U, frame.renderPasses[1]->quadList().size()); | |
3254 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size()); | |
3255 | |
3256 myHostImpl->drawLayers(frame); | |
3257 myHostImpl->didDrawAllLayers(frame); | |
3258 } | |
3259 | |
3260 // "Unocclude" surface S1 and repeat draw. | |
3261 // Must remove S2's render pass since it's cached; | |
3262 // Must keep S1 quads because texture contained external occlusion. | |
3263 WebTransformationMatrix transform = layerS2Ptr->transform(); | |
3264 transform.translate(100, 100); | |
3265 layerS2Ptr->setTransform(transform); | |
3266 { | |
3267 CCLayerTreeHostImpl::FrameData frame; | |
3268 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3269 | |
3270 // Must receive 2 render passes. | |
3271 // For Root, there are 2 quads | |
3272 // For S1, the number of quads depends on what got unoccluded, so not as
serted beyond being positive. | |
3273 // For S2, there is no render pass | |
3274 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3275 | |
3276 EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U); | |
3277 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); | |
3278 | |
3279 myHostImpl->drawLayers(frame); | |
3280 myHostImpl->didDrawAllLayers(frame); | |
3281 } | |
3282 | |
3283 // "Re-occlude" surface S1 and repeat draw. | |
3284 // Must remove S1's render pass since it is now available in full. | |
3285 // S2 has no change so must also be removed. | |
3286 transform = layerS2Ptr->transform(); | |
3287 transform.translate(-15, -15); | |
3288 layerS2Ptr->setTransform(transform); | |
3289 { | |
3290 CCLayerTreeHostImpl::FrameData frame; | |
3291 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3292 | |
3293 // Must receive 1 render pass - for the root. | |
3294 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3295 | |
3296 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); | |
3297 | |
3298 myHostImpl->drawLayers(frame); | |
3299 myHostImpl->didDrawAllLayers(frame); | |
3300 } | |
3301 } | |
3302 | |
3303 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionExternalOverInternal) | |
3304 { | |
3305 CCSettings::setPartialSwapEnabled(false); | |
3306 | |
3307 CCLayerTreeSettings settings; | |
3308 settings.minimumOcclusionTrackingSize = IntSize(); | |
3309 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, this); | |
3310 | |
3311 // Layers are structured as follows: | |
3312 // | |
3313 // R +-- S1 +- L10 (owning, drawing) | |
3314 // | +- L11 (corner, occluded by L12) | |
3315 // | +- L12 (opposite corner) | |
3316 // | | |
3317 // +-- S2 +- L20 (owning, drawing) | |
3318 // | |
3319 | |
3320 CCLayerImpl* rootPtr; | |
3321 CCLayerImpl* layerS1Ptr; | |
3322 CCLayerImpl* layerS2Ptr; | |
3323 | |
3324 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); | |
3325 | |
3326 IntSize rootSize(1000, 1000); | |
3327 | |
3328 myHostImpl->initializeRenderer(context.Pass()); | |
3329 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In
tSize(rootSize.width(), rootSize.height())); | |
3330 | |
3331 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
3332 rootPtr = root.get(); | |
3333 | |
3334 root->setAnchorPoint(FloatPoint(0, 0)); | |
3335 root->setPosition(FloatPoint(0, 0)); | |
3336 root->setBounds(rootSize); | |
3337 root->setContentBounds(rootSize); | |
3338 root->setDrawsContent(true); | |
3339 root->setMasksToBounds(true); | |
3340 myHostImpl->setRootLayer(root.Pass()); | |
3341 | |
3342 addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 400, 400), &layerS1Ptr); | |
3343 layerS1Ptr->setForceRenderSurface(true); | |
3344 | |
3345 addDrawingLayerTo(layerS1Ptr, 3, IntRect(0, 0, 300, 300), 0); // L11 | |
3346 addDrawingLayerTo(layerS1Ptr, 4, IntRect(100, 0, 300, 300), 0); // L12 | |
3347 | |
3348 addDrawingLayerTo(rootPtr, 7, IntRect(200, 0, 300, 300), &layerS2Ptr); | |
3349 layerS2Ptr->setForceRenderSurface(true); | |
3350 | |
3351 // Initial draw - must receive all quads | |
3352 { | |
3353 CCLayerTreeHostImpl::FrameData frame; | |
3354 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3355 | |
3356 // Must receive 3 render passes. | |
3357 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there
is 1 quad. | |
3358 ASSERT_EQ(3U, frame.renderPasses.size()); | |
3359 | |
3360 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3361 EXPECT_EQ(3U, frame.renderPasses[1]->quadList().size()); | |
3362 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size()); | |
3363 | |
3364 myHostImpl->drawLayers(frame); | |
3365 myHostImpl->didDrawAllLayers(frame); | |
3366 } | |
3367 | |
3368 // "Unocclude" surface S1 and repeat draw. | |
3369 // Must remove S2's render pass since it's cached; | |
3370 // Must keep S1 quads because texture contained external occlusion. | |
3371 WebTransformationMatrix transform = layerS2Ptr->transform(); | |
3372 transform.translate(300, 0); | |
3373 layerS2Ptr->setTransform(transform); | |
3374 { | |
3375 CCLayerTreeHostImpl::FrameData frame; | |
3376 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3377 | |
3378 // Must receive 2 render passes. | |
3379 // For Root, there are 2 quads | |
3380 // For S1, the number of quads depends on what got unoccluded, so not as
serted beyond being positive. | |
3381 // For S2, there is no render pass | |
3382 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3383 | |
3384 EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U); | |
3385 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); | |
3386 | |
3387 myHostImpl->drawLayers(frame); | |
3388 myHostImpl->didDrawAllLayers(frame); | |
3389 } | |
3390 } | |
3391 | |
3392 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionExternalNotAligned) | |
3393 { | |
3394 CCSettings::setPartialSwapEnabled(false); | |
3395 | |
3396 CCLayerTreeSettings settings; | |
3397 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, this); | |
3398 | |
3399 // Layers are structured as follows: | |
3400 // | |
3401 // R +-- S1 +- L10 (rotated, drawing) | |
3402 // +- L11 (occupies half surface) | |
3403 | |
3404 CCLayerImpl* rootPtr; | |
3405 CCLayerImpl* layerS1Ptr; | |
3406 | |
3407 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); | |
3408 | |
3409 IntSize rootSize(1000, 1000); | |
3410 | |
3411 myHostImpl->initializeRenderer(context.Pass()); | |
3412 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In
tSize(rootSize.width(), rootSize.height())); | |
3413 | |
3414 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
3415 rootPtr = root.get(); | |
3416 | |
3417 root->setAnchorPoint(FloatPoint(0, 0)); | |
3418 root->setPosition(FloatPoint(0, 0)); | |
3419 root->setBounds(rootSize); | |
3420 root->setContentBounds(rootSize); | |
3421 root->setDrawsContent(true); | |
3422 root->setMasksToBounds(true); | |
3423 myHostImpl->setRootLayer(root.Pass()); | |
3424 | |
3425 addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 400, 400), &layerS1Ptr); | |
3426 layerS1Ptr->setForceRenderSurface(true); | |
3427 WebTransformationMatrix transform = layerS1Ptr->transform(); | |
3428 transform.translate(200, 200); | |
3429 transform.rotate(45); | |
3430 transform.translate(-200, -200); | |
3431 layerS1Ptr->setTransform(transform); | |
3432 | |
3433 addDrawingLayerTo(layerS1Ptr, 3, IntRect(200, 0, 200, 400), 0); // L11 | |
3434 | |
3435 // Initial draw - must receive all quads | |
3436 { | |
3437 CCLayerTreeHostImpl::FrameData frame; | |
3438 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3439 | |
3440 // Must receive 2 render passes. | |
3441 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3442 | |
3443 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); | |
3444 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); | |
3445 | |
3446 myHostImpl->drawLayers(frame); | |
3447 myHostImpl->didDrawAllLayers(frame); | |
3448 } | |
3449 | |
3450 // Change opacity and draw. Verify we used cached texture. | |
3451 layerS1Ptr->setOpacity(0.2f); | |
3452 { | |
3453 CCLayerTreeHostImpl::FrameData frame; | |
3454 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3455 | |
3456 // One render pass must be gone due to cached texture. | |
3457 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3458 | |
3459 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3460 | |
3461 myHostImpl->drawLayers(frame); | |
3462 myHostImpl->didDrawAllLayers(frame); | |
3463 } | |
3464 } | |
3465 | |
3466 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionPartialSwap) | |
3467 { | |
3468 CCSettings::setPartialSwapEnabled(true); | |
3469 | |
3470 CCLayerTreeSettings settings; | |
3471 settings.minimumOcclusionTrackingSize = IntSize(); | |
3472 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, this); | |
3473 | |
3474 // Layers are structure as follows: | |
3475 // | |
3476 // R +-- S1 +- L10 (owning) | |
3477 // | +- L11 | |
3478 // | +- L12 | |
3479 // | | |
3480 // +-- S2 +- L20 (owning) | |
3481 // +- L21 | |
3482 // | |
3483 // Occlusion: | |
3484 // L12 occludes L11 (internal) | |
3485 // L20 occludes L10 (external) | |
3486 // L21 occludes L20 (internal) | |
3487 | |
3488 CCLayerImpl* rootPtr; | |
3489 CCLayerImpl* layerS1Ptr; | |
3490 CCLayerImpl* layerS2Ptr; | |
3491 | |
3492 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); | |
3493 | |
3494 IntSize rootSize(1000, 1000); | |
3495 | |
3496 myHostImpl->initializeRenderer(context.Pass()); | |
3497 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In
tSize(rootSize.width(), rootSize.height())); | |
3498 | |
3499 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
3500 rootPtr = root.get(); | |
3501 | |
3502 root->setAnchorPoint(FloatPoint(0, 0)); | |
3503 root->setPosition(FloatPoint(0, 0)); | |
3504 root->setBounds(rootSize); | |
3505 root->setContentBounds(rootSize); | |
3506 root->setDrawsContent(true); | |
3507 root->setMasksToBounds(true); | |
3508 myHostImpl->setRootLayer(root.Pass()); | |
3509 | |
3510 addDrawingLayerTo(rootPtr, 2, IntRect(300, 300, 300, 300), &layerS1Ptr); | |
3511 layerS1Ptr->setForceRenderSurface(true); | |
3512 | |
3513 addDrawingLayerTo(layerS1Ptr, 3, IntRect(10, 10, 10, 10), 0); // L11 | |
3514 addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 0, 30, 30), 0); // L12 | |
3515 | |
3516 addDrawingLayerTo(rootPtr, 5, IntRect(550, 250, 300, 400), &layerS2Ptr); | |
3517 layerS2Ptr->setForceRenderSurface(true); | |
3518 | |
3519 addDrawingLayerTo(layerS2Ptr, 6, IntRect(20, 20, 5, 5), 0); // L21 | |
3520 | |
3521 // Initial draw - must receive all quads | |
3522 { | |
3523 CCLayerTreeHostImpl::FrameData frame; | |
3524 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3525 | |
3526 // Must receive 3 render passes. | |
3527 // For Root, there are 2 quads; for S1, there are 2 quads (one is occlud
ed); for S2, there is 2 quads. | |
3528 ASSERT_EQ(3U, frame.renderPasses.size()); | |
3529 | |
3530 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); | |
3531 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); | |
3532 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size()); | |
3533 | |
3534 myHostImpl->drawLayers(frame); | |
3535 myHostImpl->didDrawAllLayers(frame); | |
3536 } | |
3537 | |
3538 // "Unocclude" surface S1 and repeat draw. | |
3539 // Must remove S2's render pass since it's cached; | |
3540 // Must keep S1 quads because texture contained external occlusion. | |
3541 WebTransformationMatrix transform = layerS2Ptr->transform(); | |
3542 transform.translate(150, 150); | |
3543 layerS2Ptr->setTransform(transform); | |
3544 { | |
3545 CCLayerTreeHostImpl::FrameData frame; | |
3546 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3547 | |
3548 // Must receive 2 render passes. | |
3549 // For Root, there are 2 quads. | |
3550 // For S1, there are 2 quads. | |
3551 // For S2, there is no render pass | |
3552 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3553 | |
3554 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size()); | |
3555 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size()); | |
3556 | |
3557 myHostImpl->drawLayers(frame); | |
3558 myHostImpl->didDrawAllLayers(frame); | |
3559 } | |
3560 | |
3561 // "Re-occlude" surface S1 and repeat draw. | |
3562 // Must remove S1's render pass since it is now available in full. | |
3563 // S2 has no change so must also be removed. | |
3564 transform = layerS2Ptr->transform(); | |
3565 transform.translate(-15, -15); | |
3566 layerS2Ptr->setTransform(transform); | |
3567 { | |
3568 CCLayerTreeHostImpl::FrameData frame; | |
3569 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3570 | |
3571 // Root render pass only. | |
3572 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3573 | |
3574 myHostImpl->drawLayers(frame); | |
3575 myHostImpl->didDrawAllLayers(frame); | |
3576 } | |
3577 } | |
3578 | |
3579 TEST_P(CCLayerTreeHostImplTest, textureCachingWithScissor) | |
3580 { | |
3581 CCSettings::setPartialSwapEnabled(false); | |
3582 | |
3583 CCLayerTreeSettings settings; | |
3584 settings.minimumOcclusionTrackingSize = IntSize(); | |
3585 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, this); | |
3586 | |
3587 /* | |
3588 Layers are created as follows: | |
3589 | |
3590 +--------------------+ | |
3591 | 1 | | |
3592 | +-----------+ | | |
3593 | | 2 | | | |
3594 | | +-------------------+ | |
3595 | | | 3 | | |
3596 | | +-------------------+ | |
3597 | | | | | |
3598 | +-----------+ | | |
3599 | | | |
3600 | | | |
3601 +--------------------+ | |
3602 | |
3603 Layers 1, 2 have render surfaces | |
3604 */ | |
3605 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1); | |
3606 scoped_ptr<CCTiledLayerImpl> child = CCTiledLayerImpl::create(2); | |
3607 scoped_ptr<CCLayerImpl> grandChild = CCLayerImpl::create(3); | |
3608 | |
3609 IntRect rootRect(0, 0, 100, 100); | |
3610 IntRect childRect(10, 10, 50, 50); | |
3611 IntRect grandChildRect(5, 5, 150, 150); | |
3612 | |
3613 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea
te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>(); | |
3614 myHostImpl->initializeRenderer(context.Pass()); | |
3615 | |
3616 root->setAnchorPoint(FloatPoint(0, 0)); | |
3617 root->setPosition(FloatPoint(rootRect.x(), rootRect.y())); | |
3618 root->setBounds(IntSize(rootRect.width(), rootRect.height())); | |
3619 root->setContentBounds(root->bounds()); | |
3620 root->setDrawsContent(true); | |
3621 root->setMasksToBounds(true); | |
3622 | |
3623 child->setAnchorPoint(FloatPoint(0, 0)); | |
3624 child->setPosition(FloatPoint(childRect.x(), childRect.y())); | |
3625 child->setOpacity(0.5); | |
3626 child->setBounds(IntSize(childRect.width(), childRect.height())); | |
3627 child->setContentBounds(child->bounds()); | |
3628 child->setDrawsContent(true); | |
3629 child->setSkipsDraw(false); | |
3630 | |
3631 // child layer has 10x10 tiles. | |
3632 OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(10, 10),
CCLayerTilingData::HasBorderTexels); | |
3633 tiler->setBounds(child->contentBounds()); | |
3634 child->setTilingData(*tiler.get()); | |
3635 | |
3636 grandChild->setAnchorPoint(FloatPoint(0, 0)); | |
3637 grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y())); | |
3638 grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height(
))); | |
3639 grandChild->setContentBounds(grandChild->bounds()); | |
3640 grandChild->setDrawsContent(true); | |
3641 | |
3642 CCTiledLayerImpl* childPtr = child.get(); | |
3643 CCRenderPass::Id childPassId(childPtr->id(), 0); | |
3644 | |
3645 child->addChild(grandChild.Pass()); | |
3646 root->addChild(child.PassAs<CCLayerImpl>()); | |
3647 myHostImpl->setRootLayer(root.Pass()); | |
3648 myHostImpl->setViewportSize(rootRect.size(), rootRect.size()); | |
3649 | |
3650 EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(chil
dPassId)); | |
3651 | |
3652 { | |
3653 CCLayerTreeHostImpl::FrameData frame; | |
3654 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3655 myHostImpl->drawLayers(frame); | |
3656 myHostImpl->didDrawAllLayers(frame); | |
3657 } | |
3658 | |
3659 // We should have cached textures for surface 2. | |
3660 EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(child
PassId)); | |
3661 | |
3662 { | |
3663 CCLayerTreeHostImpl::FrameData frame; | |
3664 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3665 myHostImpl->drawLayers(frame); | |
3666 myHostImpl->didDrawAllLayers(frame); | |
3667 } | |
3668 | |
3669 // We should still have cached textures for surface 2 after drawing with no
damage. | |
3670 EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(child
PassId)); | |
3671 | |
3672 // Damage a single tile of surface 2. | |
3673 childPtr->setUpdateRect(IntRect(10, 10, 10, 10)); | |
3674 | |
3675 { | |
3676 CCLayerTreeHostImpl::FrameData frame; | |
3677 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3678 myHostImpl->drawLayers(frame); | |
3679 myHostImpl->didDrawAllLayers(frame); | |
3680 } | |
3681 | |
3682 // We should have a cached texture for surface 2 again even though it was da
maged. | |
3683 EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(child
PassId)); | |
3684 } | |
3685 | |
3686 TEST_P(CCLayerTreeHostImplTest, surfaceTextureCaching) | |
3687 { | |
3688 CCSettings::setPartialSwapEnabled(true); | |
3689 | |
3690 CCLayerTreeSettings settings; | |
3691 settings.minimumOcclusionTrackingSize = IntSize(); | |
3692 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, this); | |
3693 | |
3694 CCLayerImpl* rootPtr; | |
3695 CCLayerImpl* intermediateLayerPtr; | |
3696 CCLayerImpl* surfaceLayerPtr; | |
3697 CCLayerImpl* childPtr; | |
3698 | |
3699 setupLayersForTextureCaching(myHostImpl.get(), rootPtr, intermediateLayerPtr
, surfaceLayerPtr, childPtr, IntSize(100, 100)); | |
3700 | |
3701 { | |
3702 CCLayerTreeHostImpl::FrameData frame; | |
3703 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3704 | |
3705 // Must receive two render passes, each with one quad | |
3706 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3707 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3708 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); | |
3709 | |
3710 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->
material()); | |
3711 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[1]->quadList()[0]); | |
3712 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3713 EXPECT_FALSE(targetPass->damageRect().isEmpty()); | |
3714 | |
3715 myHostImpl->drawLayers(frame); | |
3716 myHostImpl->didDrawAllLayers(frame); | |
3717 } | |
3718 | |
3719 // Draw without any change | |
3720 { | |
3721 CCLayerTreeHostImpl::FrameData frame; | |
3722 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3723 | |
3724 // Must receive one render pass, as the other one should be culled | |
3725 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3726 | |
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.re
nderPasses[0]->quadList()[0]); | |
3730 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3731 EXPECT_TRUE(targetPass->damageRect().isEmpty()); | |
3732 | |
3733 myHostImpl->drawLayers(frame); | |
3734 myHostImpl->didDrawAllLayers(frame); | |
3735 } | |
3736 | |
3737 // Change opacity and draw | |
3738 surfaceLayerPtr->setOpacity(0.6f); | |
3739 { | |
3740 CCLayerTreeHostImpl::FrameData frame; | |
3741 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3742 | |
3743 // Must receive one render pass, as the other one should be culled | |
3744 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3745 | |
3746 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3747 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->
material()); | |
3748 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[0]->quadList()[0]); | |
3749 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3750 EXPECT_TRUE(targetPass->damageRect().isEmpty()); | |
3751 | |
3752 myHostImpl->drawLayers(frame); | |
3753 myHostImpl->didDrawAllLayers(frame); | |
3754 } | |
3755 | |
3756 // Change less benign property and draw - should have contents changed flag | |
3757 surfaceLayerPtr->setStackingOrderChanged(true); | |
3758 { | |
3759 CCLayerTreeHostImpl::FrameData frame; | |
3760 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3761 | |
3762 // Must receive two render passes, each with one quad | |
3763 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3764 | |
3765 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3766 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->
material()); | |
3767 | |
3768 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->
material()); | |
3769 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[1]->quadList()[0]); | |
3770 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3771 EXPECT_FALSE(targetPass->damageRect().isEmpty()); | |
3772 | |
3773 myHostImpl->drawLayers(frame); | |
3774 myHostImpl->didDrawAllLayers(frame); | |
3775 } | |
3776 | |
3777 // Change opacity again, and evict the cached surface texture. | |
3778 surfaceLayerPtr->setOpacity(0.5f); | |
3779 static_cast<CCRendererGLWithReleaseTextures*>(myHostImpl->renderer())->relea
seRenderPassTextures(); | |
3780 | |
3781 // Change opacity and draw | |
3782 surfaceLayerPtr->setOpacity(0.6f); | |
3783 { | |
3784 CCLayerTreeHostImpl::FrameData frame; | |
3785 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3786 | |
3787 // Must receive two render passes | |
3788 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3789 | |
3790 // Even though not enough properties changed, the entire thing must be | |
3791 // redrawn as we don't have cached textures | |
3792 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3793 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); | |
3794 | |
3795 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->
material()); | |
3796 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[1]->quadList()[0]); | |
3797 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3798 EXPECT_TRUE(targetPass->damageRect().isEmpty()); | |
3799 | |
3800 // Was our surface evicted? | |
3801 EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(
targetPass->id())); | |
3802 | |
3803 myHostImpl->drawLayers(frame); | |
3804 myHostImpl->didDrawAllLayers(frame); | |
3805 } | |
3806 | |
3807 // Draw without any change, to make sure the state is clear | |
3808 { | |
3809 CCLayerTreeHostImpl::FrameData frame; | |
3810 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3811 | |
3812 // Must receive one render pass, as the other one should be culled | |
3813 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3814 | |
3815 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3816 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->
material()); | |
3817 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[0]->quadList()[0]); | |
3818 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3819 EXPECT_TRUE(targetPass->damageRect().isEmpty()); | |
3820 | |
3821 myHostImpl->drawLayers(frame); | |
3822 myHostImpl->didDrawAllLayers(frame); | |
3823 } | |
3824 | |
3825 // Change opacity on the intermediate layer | |
3826 WebTransformationMatrix transform = intermediateLayerPtr->transform(); | |
3827 transform.setM11(1.0001); | |
3828 intermediateLayerPtr->setTransform(transform); | |
3829 { | |
3830 CCLayerTreeHostImpl::FrameData frame; | |
3831 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3832 | |
3833 // Must receive one render pass, as the other one should be culled. | |
3834 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3835 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3836 | |
3837 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->
material()); | |
3838 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[0]->quadList()[0]); | |
3839 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3840 EXPECT_TRUE(targetPass->damageRect().isEmpty()); | |
3841 | |
3842 myHostImpl->drawLayers(frame); | |
3843 myHostImpl->didDrawAllLayers(frame); | |
3844 } | |
3845 } | |
3846 | |
3847 TEST_P(CCLayerTreeHostImplTest, surfaceTextureCachingNoPartialSwap) | |
3848 { | |
3849 CCSettings::setPartialSwapEnabled(false); | |
3850 | |
3851 CCLayerTreeSettings settings; | |
3852 settings.minimumOcclusionTrackingSize = IntSize(); | |
3853 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set
tings, this); | |
3854 | |
3855 CCLayerImpl* rootPtr; | |
3856 CCLayerImpl* intermediateLayerPtr; | |
3857 CCLayerImpl* surfaceLayerPtr; | |
3858 CCLayerImpl* childPtr; | |
3859 | |
3860 setupLayersForTextureCaching(myHostImpl.get(), rootPtr, intermediateLayerPtr
, surfaceLayerPtr, childPtr, IntSize(100, 100)); | |
3861 | |
3862 { | |
3863 CCLayerTreeHostImpl::FrameData frame; | |
3864 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3865 | |
3866 // Must receive two render passes, each with one quad | |
3867 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3868 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3869 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); | |
3870 | |
3871 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->
material()); | |
3872 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[1]->quadList()[0]); | |
3873 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3874 EXPECT_FALSE(targetPass->damageRect().isEmpty()); | |
3875 | |
3876 EXPECT_FALSE(frame.renderPasses[0]->damageRect().isEmpty()); | |
3877 EXPECT_FALSE(frame.renderPasses[1]->damageRect().isEmpty()); | |
3878 | |
3879 EXPECT_FALSE(frame.renderPasses[0]->hasOcclusionFromOutsideTargetSurface
()); | |
3880 EXPECT_FALSE(frame.renderPasses[1]->hasOcclusionFromOutsideTargetSurface
()); | |
3881 | |
3882 myHostImpl->drawLayers(frame); | |
3883 myHostImpl->didDrawAllLayers(frame); | |
3884 } | |
3885 | |
3886 // Draw without any change | |
3887 { | |
3888 CCLayerTreeHostImpl::FrameData frame; | |
3889 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3890 | |
3891 // Even though there was no change, we set the damage to entire viewport
. | |
3892 // One of the passes should be culled as a result, since contents didn't
change | |
3893 // and we have cached texture. | |
3894 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3895 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3896 | |
3897 EXPECT_TRUE(frame.renderPasses[0]->damageRect().isEmpty()); | |
3898 | |
3899 myHostImpl->drawLayers(frame); | |
3900 myHostImpl->didDrawAllLayers(frame); | |
3901 } | |
3902 | |
3903 // Change opacity and draw | |
3904 surfaceLayerPtr->setOpacity(0.6f); | |
3905 { | |
3906 CCLayerTreeHostImpl::FrameData frame; | |
3907 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3908 | |
3909 // Must receive one render pass, as the other one should be culled | |
3910 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3911 | |
3912 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3913 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->
material()); | |
3914 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[0]->quadList()[0]); | |
3915 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3916 EXPECT_TRUE(targetPass->damageRect().isEmpty()); | |
3917 | |
3918 myHostImpl->drawLayers(frame); | |
3919 myHostImpl->didDrawAllLayers(frame); | |
3920 } | |
3921 | |
3922 // Change less benign property and draw - should have contents changed flag | |
3923 surfaceLayerPtr->setStackingOrderChanged(true); | |
3924 { | |
3925 CCLayerTreeHostImpl::FrameData frame; | |
3926 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3927 | |
3928 // Must receive two render passes, each with one quad | |
3929 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3930 | |
3931 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3932 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->
material()); | |
3933 | |
3934 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->
material()); | |
3935 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[1]->quadList()[0]); | |
3936 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3937 EXPECT_FALSE(targetPass->damageRect().isEmpty()); | |
3938 | |
3939 myHostImpl->drawLayers(frame); | |
3940 myHostImpl->didDrawAllLayers(frame); | |
3941 } | |
3942 | |
3943 // Change opacity again, and evict the cached surface texture. | |
3944 surfaceLayerPtr->setOpacity(0.5f); | |
3945 static_cast<CCRendererGLWithReleaseTextures*>(myHostImpl->renderer())->relea
seRenderPassTextures(); | |
3946 | |
3947 // Change opacity and draw | |
3948 surfaceLayerPtr->setOpacity(0.6f); | |
3949 { | |
3950 CCLayerTreeHostImpl::FrameData frame; | |
3951 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3952 | |
3953 // Must receive two render passes | |
3954 ASSERT_EQ(2U, frame.renderPasses.size()); | |
3955 | |
3956 // Even though not enough properties changed, the entire thing must be | |
3957 // redrawn as we don't have cached textures | |
3958 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3959 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size()); | |
3960 | |
3961 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->
material()); | |
3962 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[1]->quadList()[0]); | |
3963 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
3964 EXPECT_TRUE(targetPass->damageRect().isEmpty()); | |
3965 | |
3966 // Was our surface evicted? | |
3967 EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(
targetPass->id())); | |
3968 | |
3969 myHostImpl->drawLayers(frame); | |
3970 myHostImpl->didDrawAllLayers(frame); | |
3971 } | |
3972 | |
3973 // Draw without any change, to make sure the state is clear | |
3974 { | |
3975 CCLayerTreeHostImpl::FrameData frame; | |
3976 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3977 | |
3978 // Even though there was no change, we set the damage to entire viewport
. | |
3979 // One of the passes should be culled as a result, since contents didn't
change | |
3980 // and we have cached texture. | |
3981 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3982 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3983 | |
3984 myHostImpl->drawLayers(frame); | |
3985 myHostImpl->didDrawAllLayers(frame); | |
3986 } | |
3987 | |
3988 // Change opacity on the intermediate layer | |
3989 WebTransformationMatrix transform = intermediateLayerPtr->transform(); | |
3990 transform.setM11(1.0001); | |
3991 intermediateLayerPtr->setTransform(transform); | |
3992 { | |
3993 CCLayerTreeHostImpl::FrameData frame; | |
3994 EXPECT_TRUE(myHostImpl->prepareToDraw(frame)); | |
3995 | |
3996 // Must receive one render pass, as the other one should be culled. | |
3997 ASSERT_EQ(1U, frame.renderPasses.size()); | |
3998 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size()); | |
3999 | |
4000 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->
material()); | |
4001 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re
nderPasses[0]->quadList()[0]); | |
4002 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId
()); | |
4003 EXPECT_TRUE(targetPass->damageRect().isEmpty()); | |
4004 | |
4005 myHostImpl->drawLayers(frame); | |
4006 myHostImpl->didDrawAllLayers(frame); | |
4007 } | |
4008 } | |
4009 | |
4010 TEST_P(CCLayerTreeHostImplTest, releaseContentsTextureShouldTriggerCommit) | |
4011 { | |
4012 m_hostImpl->releaseContentsTextures(); | |
4013 EXPECT_TRUE(m_didRequestCommit); | |
4014 } | |
4015 | |
4016 struct RenderPassRemovalTestData : public CCLayerTreeHostImpl::FrameData { | |
4017 ScopedPtrHashMap<CCRenderPass::Id, CCRenderPass> renderPassCache; | |
4018 scoped_ptr<CCSharedQuadState> sharedQuadState; | |
4019 }; | |
4020 | |
4021 class CCTestRenderer : public CCRendererGL, public CCRendererClient { | |
4022 public: | |
4023 static PassOwnPtr<CCTestRenderer> create(CCResourceProvider* resourceProvide
r) | |
4024 { | |
4025 OwnPtr<CCTestRenderer> renderer(adoptPtr(new CCTestRenderer(resourceProv
ider))); | |
4026 if (!renderer->initialize()) | |
4027 return nullptr; | |
4028 | |
4029 return renderer.release(); | |
4030 } | |
4031 | |
4032 void clearCachedTextures() { m_textures.clear(); } | |
4033 void setHaveCachedResourcesForRenderPassId(CCRenderPass::Id id) { m_textures
.insert(id); } | |
4034 | |
4035 virtual bool haveCachedResourcesForRenderPassId(CCRenderPass::Id id) const O
VERRIDE { return m_textures.count(id); } | |
4036 | |
4037 // CCRendererClient implementation. | |
4038 virtual const IntSize& deviceViewportSize() const OVERRIDE { return m_viewpo
rtSize; } | |
4039 virtual const CCLayerTreeSettings& settings() const OVERRIDE { return m_sett
ings; } | |
4040 virtual void didLoseContext() OVERRIDE { } | |
4041 virtual void onSwapBuffersComplete() OVERRIDE { } | |
4042 virtual void setFullRootLayerDamage() OVERRIDE { } | |
4043 virtual void releaseContentsTextures() OVERRIDE { } | |
4044 virtual void setMemoryAllocationLimitBytes(size_t) OVERRIDE { } | |
4045 | |
4046 protected: | |
4047 CCTestRenderer(CCResourceProvider* resourceProvider) : CCRendererGL(this, re
sourceProvider) { } | |
4048 | |
4049 private: | |
4050 CCLayerTreeSettings m_settings; | |
4051 IntSize m_viewportSize; | |
4052 base::hash_set<CCRenderPass::Id> m_textures; | |
4053 }; | |
4054 | |
4055 static void configureRenderPassTestData(const char* testScript, RenderPassRemova
lTestData& testData, CCTestRenderer* renderer) | |
4056 { | |
4057 renderer->clearCachedTextures(); | |
4058 | |
4059 // One shared state for all quads - we don't need the correct details | |
4060 testData.sharedQuadState = CCSharedQuadState::create(WebTransformationMatrix
(), IntRect(), IntRect(), 1.0, true); | |
4061 | |
4062 const char* currentChar = testScript; | |
4063 | |
4064 // Pre-create root pass | |
4065 CCRenderPass::Id rootRenderPassId = CCRenderPass::Id(testScript[0], testScri
pt[1]); | |
4066 testData.renderPassCache.add(rootRenderPassId, CCRenderPass::create(rootRend
erPassId, IntRect(), WebTransformationMatrix())); | |
4067 while (*currentChar) { | |
4068 int layerId = *currentChar; | |
4069 currentChar++; | |
4070 ASSERT_TRUE(currentChar); | |
4071 int index = *currentChar; | |
4072 currentChar++; | |
4073 | |
4074 CCRenderPass::Id renderPassId = CCRenderPass::Id(layerId, index); | |
4075 | |
4076 bool isReplica = false; | |
4077 if (!testData.renderPassCache.contains(renderPassId)) | |
4078 isReplica = true; | |
4079 | |
4080 scoped_ptr<CCRenderPass> renderPass = testData.renderPassCache.take(rend
erPassId); | |
4081 | |
4082 // Cycle through quad data and create all quads | |
4083 while (*currentChar && *currentChar != '\n') { | |
4084 if (*currentChar == 's') { | |
4085 // Solid color draw quad | |
4086 scoped_ptr<CCSolidColorDrawQuad> quad = CCSolidColorDrawQuad::cr
eate(testData.sharedQuadState.get(), IntRect(0, 0, 10, 10), SK_ColorWHITE); | |
4087 | |
4088 static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(qua
d.PassAs<CCDrawQuad>()); | |
4089 currentChar++; | |
4090 } else if ((*currentChar >= 'A') && (*currentChar <= 'Z')) { | |
4091 // RenderPass draw quad | |
4092 int layerId = *currentChar; | |
4093 currentChar++; | |
4094 ASSERT_TRUE(currentChar); | |
4095 int index = *currentChar; | |
4096 currentChar++; | |
4097 CCRenderPass::Id newRenderPassId = CCRenderPass::Id(layerId, ind
ex); | |
4098 ASSERT_NE(rootRenderPassId, newRenderPassId); | |
4099 bool hasTexture = false; | |
4100 bool contentsChanged = true; | |
4101 | |
4102 if (*currentChar == '[') { | |
4103 currentChar++; | |
4104 while (*currentChar && *currentChar != ']') { | |
4105 switch (*currentChar) { | |
4106 case 'c': | |
4107 contentsChanged = false; | |
4108 break; | |
4109 case 't': | |
4110 hasTexture = true; | |
4111 break; | |
4112 } | |
4113 currentChar++; | |
4114 } | |
4115 if (*currentChar == ']') | |
4116 currentChar++; | |
4117 } | |
4118 | |
4119 if (testData.renderPassCache.find(newRenderPassId) == testData.r
enderPassCache.end()) { | |
4120 if (hasTexture) | |
4121 renderer->setHaveCachedResourcesForRenderPassId(newRende
rPassId); | |
4122 | |
4123 testData.renderPassCache.add(newRenderPassId, CCTestRenderPa
ss::create(newRenderPassId, IntRect(), WebTransformationMatrix())); | |
4124 } | |
4125 | |
4126 IntRect quadRect = IntRect(0, 0, 1, 1); | |
4127 IntRect contentsChangedRect = contentsChanged ? quadRect : IntRe
ct(); | |
4128 scoped_ptr<CCRenderPassDrawQuad> quad = CCRenderPassDrawQuad::cr
eate(testData.sharedQuadState.get(), quadRect, newRenderPassId, isReplica, 1, co
ntentsChangedRect, 1, 1, 0, 0); | |
4129 static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(qua
d.PassAs<CCDrawQuad>()); | |
4130 } | |
4131 } | |
4132 testData.renderPasses.insert(testData.renderPasses.begin(), renderPass.g
et()); | |
4133 testData.renderPassesById.add(renderPassId, renderPass.Pass()); | |
4134 if (*currentChar) | |
4135 currentChar++; | |
4136 } | |
4137 } | |
4138 | |
4139 void dumpRenderPassTestData(const RenderPassRemovalTestData& testData, char* buf
fer) | |
4140 { | |
4141 char* pos = buffer; | |
4142 for (CCRenderPassList::const_reverse_iterator it = testData.renderPasses.rbe
gin(); it != testData.renderPasses.rend(); ++it) { | |
4143 const CCRenderPass* currentPass = *it; | |
4144 *pos = currentPass->id().layerId; | |
4145 pos++; | |
4146 *pos = currentPass->id().index; | |
4147 pos++; | |
4148 | |
4149 CCQuadList::const_iterator quadListIterator = currentPass->quadList().be
gin(); | |
4150 while (quadListIterator != currentPass->quadList().end()) { | |
4151 CCDrawQuad* currentQuad = *quadListIterator; | |
4152 switch (currentQuad->material()) { | |
4153 case CCDrawQuad::SolidColor: | |
4154 *pos = 's'; | |
4155 pos++; | |
4156 break; | |
4157 case CCDrawQuad::RenderPass: | |
4158 *pos = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPa
ssId().layerId; | |
4159 pos++; | |
4160 *pos = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPa
ssId().index; | |
4161 pos++; | |
4162 break; | |
4163 default: | |
4164 *pos = 'x'; | |
4165 pos++; | |
4166 break; | |
4167 } | |
4168 | |
4169 quadListIterator++; | |
4170 } | |
4171 *pos = '\n'; | |
4172 pos++; | |
4173 } | |
4174 *pos = '\0'; | |
4175 } | |
4176 | |
4177 // Each CCRenderPassList is represented by a string which describes the configur
ation. | |
4178 // The syntax of the string is as follows: | |
4179 // | |
4180 // RsssssX[c]ssYsssZ[t]ssW[
ct] | |
4181 // Identifies the render pass---------------------------^ ^^^ ^ ^ ^ ^
^ | |
4182 // These are solid color quads-----------------------------+ | | | |
| | |
4183 // Identifies RenderPassDrawQuad's RenderPass-----------------+ | | |
| | |
4184 // This quad's contents didn't change---------------------------+ | |
| | |
4185 // This quad's contents changed and it has no texture---------------+ |
| | |
4186 // This quad has texture but its contents changed-------------------------+
| | |
4187 // This quad's contents didn't change and it has texture - will be removed------
+ | |
4188 // | |
4189 // Expected results have exactly the same syntax, except they do not use square
brackets, | |
4190 // since we only check the structure, not attributes. | |
4191 // | |
4192 // Test case configuration consists of initialization script and expected result
s, | |
4193 // all in the same format. | |
4194 struct TestCase { | |
4195 const char* name; | |
4196 const char* initScript; | |
4197 const char* expectedResult; | |
4198 }; | |
4199 | |
4200 TestCase removeRenderPassesCases[] = | |
4201 { | |
4202 { | |
4203 "Single root pass", | |
4204 "R0ssss\n", | |
4205 "R0ssss\n" | |
4206 }, { | |
4207 "Single pass - no quads", | |
4208 "R0\n", | |
4209 "R0\n" | |
4210 }, { | |
4211 "Two passes, no removal", | |
4212 "R0ssssA0sss\n" | |
4213 "A0ssss\n", | |
4214 "R0ssssA0sss\n" | |
4215 "A0ssss\n" | |
4216 }, { | |
4217 "Two passes, remove last", | |
4218 "R0ssssA0[ct]sss\n" | |
4219 "A0ssss\n", | |
4220 "R0ssssA0sss\n" | |
4221 }, { | |
4222 "Have texture but contents changed - leave pass", | |
4223 "R0ssssA0[t]sss\n" | |
4224 "A0ssss\n", | |
4225 "R0ssssA0sss\n" | |
4226 "A0ssss\n" | |
4227 }, { | |
4228 "Contents didn't change but no texture - leave pass", | |
4229 "R0ssssA0[c]sss\n" | |
4230 "A0ssss\n", | |
4231 "R0ssssA0sss\n" | |
4232 "A0ssss\n" | |
4233 }, { | |
4234 "Replica: two quads reference the same pass; remove", | |
4235 "R0ssssA0[ct]A0[ct]sss\n" | |
4236 "A0ssss\n", | |
4237 "R0ssssA0A0sss\n" | |
4238 }, { | |
4239 "Replica: two quads reference the same pass; leave", | |
4240 "R0ssssA0[c]A0[c]sss\n" | |
4241 "A0ssss\n", | |
4242 "R0ssssA0A0sss\n" | |
4243 "A0ssss\n", | |
4244 }, { | |
4245 "Many passes, remove all", | |
4246 "R0ssssA0[ct]sss\n" | |
4247 "A0sssB0[ct]C0[ct]s\n" | |
4248 "B0sssD0[ct]ssE0[ct]F0[ct]\n" | |
4249 "E0ssssss\n" | |
4250 "C0G0[ct]\n" | |
4251 "D0sssssss\n" | |
4252 "F0sssssss\n" | |
4253 "G0sss\n", | |
4254 | |
4255 "R0ssssA0sss\n" | |
4256 }, { | |
4257 "Deep recursion, remove all", | |
4258 | |
4259 "R0sssssA0[ct]ssss\n" | |
4260 "A0ssssB0sss\n" | |
4261 "B0C0\n" | |
4262 "C0D0\n" | |
4263 "D0E0\n" | |
4264 "E0F0\n" | |
4265 "F0G0\n" | |
4266 "G0H0\n" | |
4267 "H0sssI0sss\n" | |
4268 "I0J0\n" | |
4269 "J0ssss\n", | |
4270 | |
4271 "R0sssssA0ssss\n" | |
4272 }, { | |
4273 "Wide recursion, remove all", | |
4274 "R0A0[ct]B0[ct]C0[ct]D0[ct]E0[ct]F0[ct]G0[ct]H0[ct]I0[ct]J0[ct]\n" | |
4275 "A0s\n" | |
4276 "B0s\n" | |
4277 "C0ssss\n" | |
4278 "D0ssss\n" | |
4279 "E0s\n" | |
4280 "F0\n" | |
4281 "G0s\n" | |
4282 "H0s\n" | |
4283 "I0s\n" | |
4284 "J0ssss\n", | |
4285 | |
4286 "R0A0B0C0D0E0F0G0H0I0J0\n" | |
4287 }, { | |
4288 "Remove passes regardless of cache state", | |
4289 "R0ssssA0[ct]sss\n" | |
4290 "A0sssB0C0s\n" | |
4291 "B0sssD0[c]ssE0[t]F0\n" | |
4292 "E0ssssss\n" | |
4293 "C0G0\n" | |
4294 "D0sssssss\n" | |
4295 "F0sssssss\n" | |
4296 "G0sss\n", | |
4297 | |
4298 "R0ssssA0sss\n" | |
4299 }, { | |
4300 "Leave some passes, remove others", | |
4301 | |
4302 "R0ssssA0[c]sss\n" | |
4303 "A0sssB0[t]C0[ct]s\n" | |
4304 "B0sssD0[c]ss\n" | |
4305 "C0G0\n" | |
4306 "D0sssssss\n" | |
4307 "G0sss\n", | |
4308 | |
4309 "R0ssssA0sss\n" | |
4310 "A0sssB0C0s\n" | |
4311 "B0sssD0ss\n" | |
4312 "D0sssssss\n" | |
4313 }, { | |
4314 0, 0, 0 | |
4315 } | |
4316 }; | |
4317 | |
4318 static void verifyRenderPassTestData(TestCase& testCase, RenderPassRemovalTestDa
ta& testData) | |
4319 { | |
4320 char actualResult[1024]; | |
4321 dumpRenderPassTestData(testData, actualResult); | |
4322 EXPECT_STREQ(testCase.expectedResult, actualResult) << "In test case: " << t
estCase.name; | |
4323 } | |
4324 | |
4325 TEST_P(CCLayerTreeHostImplTest, testRemoveRenderPasses) | |
4326 { | |
4327 scoped_ptr<CCGraphicsContext> context(createContext()); | |
4328 ASSERT_TRUE(context->context3D()); | |
4329 OwnPtr<CCResourceProvider> resourceProvider(CCResourceProvider::create(conte
xt.get())); | |
4330 | |
4331 OwnPtr<CCTestRenderer> renderer(CCTestRenderer::create(resourceProvider.get(
))); | |
4332 | |
4333 int testCaseIndex = 0; | |
4334 while (removeRenderPassesCases[testCaseIndex].name) { | |
4335 RenderPassRemovalTestData testData; | |
4336 configureRenderPassTestData(removeRenderPassesCases[testCaseIndex].initS
cript, testData, renderer.get()); | |
4337 CCLayerTreeHostImpl::removeRenderPasses(CCLayerTreeHostImpl::CullRenderP
assesWithCachedTextures(*renderer), testData); | |
4338 verifyRenderPassTestData(removeRenderPassesCases[testCaseIndex], testDat
a); | |
4339 testCaseIndex++; | |
4340 } | |
4341 } | |
4342 | |
4343 INSTANTIATE_TEST_CASE_P(CCLayerTreeHostImplTests, | |
4344 CCLayerTreeHostImplTest, | |
4345 ::testing::Values(false, true)); | |
4346 | |
4347 } // namespace | |
OLD | NEW |