| 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 |