OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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 "cc/output/copy_output_request.h" |
| 6 #include "cc/output/copy_output_result.h" |
| 7 #include "cc/test/fake_content_layer.h" |
| 8 #include "cc/test/fake_content_layer_client.h" |
| 9 #include "cc/test/fake_output_surface.h" |
| 10 #include "cc/test/layer_tree_test.h" |
| 11 #include "cc/trees/layer_tree_impl.h" |
| 12 #include "gpu/GLES2/gl2extchromium.h" |
| 13 |
| 14 namespace cc { |
| 15 namespace { |
| 16 |
| 17 // These tests only use direct rendering, as there is no output to copy for |
| 18 // delegated renderers. |
| 19 class LayerTreeHostCopyRequestTest : public LayerTreeTest {}; |
| 20 |
| 21 class LayerTreeHostCopyRequestTestMultipleRequests |
| 22 : public LayerTreeHostCopyRequestTest { |
| 23 protected: |
| 24 virtual void SetupTree() OVERRIDE { |
| 25 root = FakeContentLayer::Create(&client_); |
| 26 root->SetBounds(gfx::Size(20, 20)); |
| 27 |
| 28 child = FakeContentLayer::Create(&client_); |
| 29 child->SetBounds(gfx::Size(10, 10)); |
| 30 root->AddChild(child); |
| 31 |
| 32 layer_tree_host()->SetRootLayer(root); |
| 33 LayerTreeHostCopyRequestTest::SetupTree(); |
| 34 } |
| 35 |
| 36 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } |
| 37 |
| 38 virtual void DidCommitAndDrawFrame() OVERRIDE { WaitForCallback(); } |
| 39 |
| 40 void WaitForCallback() { |
| 41 base::MessageLoop::current()->PostTask( |
| 42 FROM_HERE, |
| 43 base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::NextStep, |
| 44 base::Unretained(this))); |
| 45 } |
| 46 |
| 47 void NextStep() { |
| 48 int frame = layer_tree_host()->source_frame_number(); |
| 49 switch (frame) { |
| 50 case 1: |
| 51 child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( |
| 52 base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests:: |
| 53 CopyOutputCallback, |
| 54 base::Unretained(this)))); |
| 55 EXPECT_EQ(0u, callbacks_.size()); |
| 56 break; |
| 57 case 2: |
| 58 if (callbacks_.size() < 1u) { |
| 59 WaitForCallback(); |
| 60 return; |
| 61 } |
| 62 EXPECT_EQ(1u, callbacks_.size()); |
| 63 EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[0].ToString()); |
| 64 |
| 65 child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( |
| 66 base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests:: |
| 67 CopyOutputCallback, |
| 68 base::Unretained(this)))); |
| 69 root->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( |
| 70 base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests:: |
| 71 CopyOutputCallback, |
| 72 base::Unretained(this)))); |
| 73 child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( |
| 74 base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests:: |
| 75 CopyOutputCallback, |
| 76 base::Unretained(this)))); |
| 77 EXPECT_EQ(1u, callbacks_.size()); |
| 78 break; |
| 79 case 3: |
| 80 if (callbacks_.size() < 4u) { |
| 81 WaitForCallback(); |
| 82 return; |
| 83 } |
| 84 EXPECT_EQ(4u, callbacks_.size()); |
| 85 // The child was copied to a bitmap and passed back twice. |
| 86 EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[1].ToString()); |
| 87 EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[2].ToString()); |
| 88 // The root was copied to a bitmap and passed back also. |
| 89 EXPECT_EQ(gfx::Size(20, 20).ToString(), callbacks_[3].ToString()); |
| 90 EndTest(); |
| 91 break; |
| 92 } |
| 93 } |
| 94 |
| 95 void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { |
| 96 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); |
| 97 EXPECT_TRUE(result->HasBitmap()); |
| 98 scoped_ptr<SkBitmap> bitmap = result->TakeBitmap().Pass(); |
| 99 EXPECT_EQ(result->size().ToString(), |
| 100 gfx::Size(bitmap->width(), bitmap->height()).ToString()); |
| 101 callbacks_.push_back(result->size()); |
| 102 } |
| 103 |
| 104 virtual void AfterTest() OVERRIDE { EXPECT_EQ(4u, callbacks_.size()); } |
| 105 |
| 106 virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) |
| 107 OVERRIDE { |
| 108 scoped_ptr<FakeOutputSurface> output_surface; |
| 109 if (use_gl_renderer_) { |
| 110 output_surface = FakeOutputSurface::Create3d().Pass(); |
| 111 } else { |
| 112 output_surface = FakeOutputSurface::CreateSoftware( |
| 113 make_scoped_ptr(new SoftwareOutputDevice)).Pass(); |
| 114 } |
| 115 return output_surface.PassAs<OutputSurface>(); |
| 116 } |
| 117 |
| 118 bool use_gl_renderer_; |
| 119 std::vector<gfx::Size> callbacks_; |
| 120 FakeContentLayerClient client_; |
| 121 scoped_refptr<FakeContentLayer> root; |
| 122 scoped_refptr<FakeContentLayer> child; |
| 123 }; |
| 124 |
| 125 // Readback can't be done with a delegating renderer. |
| 126 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| 127 GLRenderer_RunSingleThread) { |
| 128 use_gl_renderer_ = true; |
| 129 RunTest(false, false, false); |
| 130 } |
| 131 |
| 132 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| 133 GLRenderer_RunMultiThread_MainThreadPainting) { |
| 134 use_gl_renderer_ = true; |
| 135 RunTest(true, false, false); |
| 136 } |
| 137 |
| 138 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| 139 SoftwareRenderer_RunSingleThread) { |
| 140 use_gl_renderer_ = false; |
| 141 RunTest(false, false, false); |
| 142 } |
| 143 |
| 144 TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| 145 SoftwareRenderer_RunMultiThread_MainThreadPainting) { |
| 146 use_gl_renderer_ = false; |
| 147 RunTest(true, false, false); |
| 148 } |
| 149 |
| 150 class LayerTreeHostCopyRequestTestLayerDestroyed |
| 151 : public LayerTreeHostCopyRequestTest { |
| 152 protected: |
| 153 virtual void SetupTree() OVERRIDE { |
| 154 root_ = FakeContentLayer::Create(&client_); |
| 155 root_->SetBounds(gfx::Size(20, 20)); |
| 156 |
| 157 main_destroyed_ = FakeContentLayer::Create(&client_); |
| 158 main_destroyed_->SetBounds(gfx::Size(15, 15)); |
| 159 root_->AddChild(main_destroyed_); |
| 160 |
| 161 impl_destroyed_ = FakeContentLayer::Create(&client_); |
| 162 impl_destroyed_->SetBounds(gfx::Size(10, 10)); |
| 163 root_->AddChild(impl_destroyed_); |
| 164 |
| 165 layer_tree_host()->SetRootLayer(root_); |
| 166 LayerTreeHostCopyRequestTest::SetupTree(); |
| 167 } |
| 168 |
| 169 virtual void BeginTest() OVERRIDE { |
| 170 callback_count_ = 0; |
| 171 PostSetNeedsCommitToMainThread(); |
| 172 } |
| 173 |
| 174 virtual void DidCommit() OVERRIDE { |
| 175 int frame = layer_tree_host()->source_frame_number(); |
| 176 switch (frame) { |
| 177 case 1: |
| 178 main_destroyed_->RequestCopyOfOutput( |
| 179 CopyOutputRequest::CreateBitmapRequest(base::Bind( |
| 180 &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback, |
| 181 base::Unretained(this)))); |
| 182 impl_destroyed_->RequestCopyOfOutput( |
| 183 CopyOutputRequest::CreateBitmapRequest(base::Bind( |
| 184 &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback, |
| 185 base::Unretained(this)))); |
| 186 EXPECT_EQ(0, callback_count_); |
| 187 |
| 188 // Destroy the main thread layer right away. |
| 189 main_destroyed_->RemoveFromParent(); |
| 190 main_destroyed_ = NULL; |
| 191 |
| 192 // Should callback with a NULL bitmap. |
| 193 EXPECT_EQ(1, callback_count_); |
| 194 |
| 195 // Prevent drawing so we can't make a copy of the impl_destroyed layer. |
| 196 layer_tree_host()->SetViewportSize(gfx::Size()); |
| 197 break; |
| 198 case 2: |
| 199 // Flush the message loops and make sure the callbacks run. |
| 200 layer_tree_host()->SetNeedsCommit(); |
| 201 break; |
| 202 case 3: |
| 203 // No drawing means no readback yet. |
| 204 EXPECT_EQ(1, callback_count_); |
| 205 |
| 206 // Destroy the impl thread layer. |
| 207 impl_destroyed_->RemoveFromParent(); |
| 208 impl_destroyed_ = NULL; |
| 209 |
| 210 // No callback yet because it's on the impl side. |
| 211 EXPECT_EQ(1, callback_count_); |
| 212 break; |
| 213 case 4: |
| 214 // Flush the message loops and make sure the callbacks run. |
| 215 layer_tree_host()->SetNeedsCommit(); |
| 216 break; |
| 217 case 5: |
| 218 // We should get another callback with a NULL bitmap. |
| 219 EXPECT_EQ(2, callback_count_); |
| 220 EndTest(); |
| 221 break; |
| 222 } |
| 223 } |
| 224 |
| 225 void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { |
| 226 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); |
| 227 EXPECT_TRUE(result->IsEmpty()); |
| 228 ++callback_count_; |
| 229 } |
| 230 |
| 231 virtual void AfterTest() OVERRIDE {} |
| 232 |
| 233 int callback_count_; |
| 234 FakeContentLayerClient client_; |
| 235 scoped_refptr<FakeContentLayer> root_; |
| 236 scoped_refptr<FakeContentLayer> main_destroyed_; |
| 237 scoped_refptr<FakeContentLayer> impl_destroyed_; |
| 238 }; |
| 239 |
| 240 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestLayerDestroyed); |
| 241 |
| 242 class LayerTreeHostCopyRequestTestInHiddenSubtree |
| 243 : public LayerTreeHostCopyRequestTest { |
| 244 protected: |
| 245 virtual void SetupTree() OVERRIDE { |
| 246 root_ = FakeContentLayer::Create(&client_); |
| 247 root_->SetBounds(gfx::Size(20, 20)); |
| 248 |
| 249 grand_parent_layer_ = FakeContentLayer::Create(&client_); |
| 250 grand_parent_layer_->SetBounds(gfx::Size(15, 15)); |
| 251 root_->AddChild(grand_parent_layer_); |
| 252 |
| 253 // parent_layer_ owns a render surface. |
| 254 parent_layer_ = FakeContentLayer::Create(&client_); |
| 255 parent_layer_->SetBounds(gfx::Size(15, 15)); |
| 256 parent_layer_->SetForceRenderSurface(true); |
| 257 grand_parent_layer_->AddChild(parent_layer_); |
| 258 |
| 259 copy_layer_ = FakeContentLayer::Create(&client_); |
| 260 copy_layer_->SetBounds(gfx::Size(10, 10)); |
| 261 parent_layer_->AddChild(copy_layer_); |
| 262 |
| 263 layer_tree_host()->SetRootLayer(root_); |
| 264 LayerTreeHostCopyRequestTest::SetupTree(); |
| 265 } |
| 266 |
| 267 void AddCopyRequest(Layer* layer) { |
| 268 layer->RequestCopyOfOutput( |
| 269 CopyOutputRequest::CreateBitmapRequest(base::Bind( |
| 270 &LayerTreeHostCopyRequestTestInHiddenSubtree::CopyOutputCallback, |
| 271 base::Unretained(this)))); |
| 272 } |
| 273 |
| 274 virtual void BeginTest() OVERRIDE { |
| 275 callback_count_ = 0; |
| 276 PostSetNeedsCommitToMainThread(); |
| 277 |
| 278 AddCopyRequest(copy_layer_.get()); |
| 279 } |
| 280 |
| 281 void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { |
| 282 ++callback_count_; |
| 283 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); |
| 284 EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()) |
| 285 << callback_count_; |
| 286 switch (callback_count_) { |
| 287 case 1: |
| 288 // Hide the copy request layer. |
| 289 grand_parent_layer_->SetHideLayerAndSubtree(false); |
| 290 parent_layer_->SetHideLayerAndSubtree(false); |
| 291 copy_layer_->SetHideLayerAndSubtree(true); |
| 292 AddCopyRequest(copy_layer_.get()); |
| 293 break; |
| 294 case 2: |
| 295 // Hide the copy request layer's parent only. |
| 296 grand_parent_layer_->SetHideLayerAndSubtree(false); |
| 297 parent_layer_->SetHideLayerAndSubtree(true); |
| 298 copy_layer_->SetHideLayerAndSubtree(false); |
| 299 AddCopyRequest(copy_layer_.get()); |
| 300 break; |
| 301 case 3: |
| 302 // Hide the copy request layer's grand parent only. |
| 303 grand_parent_layer_->SetHideLayerAndSubtree(true); |
| 304 parent_layer_->SetHideLayerAndSubtree(false); |
| 305 copy_layer_->SetHideLayerAndSubtree(false); |
| 306 AddCopyRequest(copy_layer_.get()); |
| 307 break; |
| 308 case 4: |
| 309 // Hide the copy request layer's parent and grandparent. |
| 310 grand_parent_layer_->SetHideLayerAndSubtree(true); |
| 311 parent_layer_->SetHideLayerAndSubtree(true); |
| 312 copy_layer_->SetHideLayerAndSubtree(false); |
| 313 AddCopyRequest(copy_layer_.get()); |
| 314 break; |
| 315 case 5: |
| 316 // Hide the copy request layer as well as its parent and grandparent. |
| 317 grand_parent_layer_->SetHideLayerAndSubtree(true); |
| 318 parent_layer_->SetHideLayerAndSubtree(true); |
| 319 copy_layer_->SetHideLayerAndSubtree(true); |
| 320 AddCopyRequest(copy_layer_.get()); |
| 321 break; |
| 322 case 6: |
| 323 EndTest(); |
| 324 break; |
| 325 } |
| 326 } |
| 327 |
| 328 virtual void AfterTest() OVERRIDE {} |
| 329 |
| 330 int callback_count_; |
| 331 FakeContentLayerClient client_; |
| 332 scoped_refptr<FakeContentLayer> root_; |
| 333 scoped_refptr<FakeContentLayer> grand_parent_layer_; |
| 334 scoped_refptr<FakeContentLayer> parent_layer_; |
| 335 scoped_refptr<FakeContentLayer> copy_layer_; |
| 336 }; |
| 337 |
| 338 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( |
| 339 LayerTreeHostCopyRequestTestInHiddenSubtree); |
| 340 |
| 341 class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest |
| 342 : public LayerTreeHostCopyRequestTest { |
| 343 protected: |
| 344 virtual void SetupTree() OVERRIDE { |
| 345 root_ = FakeContentLayer::Create(&client_); |
| 346 root_->SetBounds(gfx::Size(20, 20)); |
| 347 |
| 348 grand_parent_layer_ = FakeContentLayer::Create(&client_); |
| 349 grand_parent_layer_->SetBounds(gfx::Size(15, 15)); |
| 350 grand_parent_layer_->SetHideLayerAndSubtree(true); |
| 351 root_->AddChild(grand_parent_layer_); |
| 352 |
| 353 // parent_layer_ owns a render surface. |
| 354 parent_layer_ = FakeContentLayer::Create(&client_); |
| 355 parent_layer_->SetBounds(gfx::Size(15, 15)); |
| 356 parent_layer_->SetForceRenderSurface(true); |
| 357 grand_parent_layer_->AddChild(parent_layer_); |
| 358 |
| 359 copy_layer_ = FakeContentLayer::Create(&client_); |
| 360 copy_layer_->SetBounds(gfx::Size(10, 10)); |
| 361 parent_layer_->AddChild(copy_layer_); |
| 362 |
| 363 layer_tree_host()->SetRootLayer(root_); |
| 364 LayerTreeHostCopyRequestTest::SetupTree(); |
| 365 } |
| 366 |
| 367 virtual void BeginTest() OVERRIDE { |
| 368 did_draw_ = false; |
| 369 PostSetNeedsCommitToMainThread(); |
| 370 |
| 371 copy_layer_->RequestCopyOfOutput( |
| 372 CopyOutputRequest::CreateBitmapRequest(base::Bind( |
| 373 &LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest:: |
| 374 CopyOutputCallback, |
| 375 base::Unretained(this)))); |
| 376 } |
| 377 |
| 378 void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { |
| 379 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); |
| 380 EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()); |
| 381 EndTest(); |
| 382 } |
| 383 |
| 384 virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { |
| 385 Renderer* renderer = host_impl->renderer(); |
| 386 |
| 387 LayerImpl* root = host_impl->active_tree()->root_layer(); |
| 388 LayerImpl* grand_parent = root->children()[0]; |
| 389 LayerImpl* parent = grand_parent->children()[0]; |
| 390 LayerImpl* copy_layer = parent->children()[0]; |
| 391 |
| 392 // |parent| owns a surface, but it was hidden and not part of the copy |
| 393 // request so it should not allocate any resource. |
| 394 EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting( |
| 395 parent->render_surface()->RenderPassId())); |
| 396 |
| 397 // |copy_layer| should have been rendered to a texture since it was needed |
| 398 // for a copy request. |
| 399 EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting( |
| 400 copy_layer->render_surface()->RenderPassId())); |
| 401 |
| 402 did_draw_ = true; |
| 403 } |
| 404 |
| 405 virtual void AfterTest() OVERRIDE { EXPECT_TRUE(did_draw_); } |
| 406 |
| 407 FakeContentLayerClient client_; |
| 408 bool did_draw_; |
| 409 scoped_refptr<FakeContentLayer> root_; |
| 410 scoped_refptr<FakeContentLayer> grand_parent_layer_; |
| 411 scoped_refptr<FakeContentLayer> parent_layer_; |
| 412 scoped_refptr<FakeContentLayer> copy_layer_; |
| 413 }; |
| 414 |
| 415 // No output to copy for delegated renderers. |
| 416 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( |
| 417 LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest); |
| 418 |
| 419 class LayerTreeHostCopyRequestTestClippedOut |
| 420 : public LayerTreeHostCopyRequestTest { |
| 421 protected: |
| 422 virtual void SetupTree() OVERRIDE { |
| 423 root_ = FakeContentLayer::Create(&client_); |
| 424 root_->SetBounds(gfx::Size(20, 20)); |
| 425 |
| 426 parent_layer_ = FakeContentLayer::Create(&client_); |
| 427 parent_layer_->SetBounds(gfx::Size(15, 15)); |
| 428 parent_layer_->SetMasksToBounds(true); |
| 429 root_->AddChild(parent_layer_); |
| 430 |
| 431 copy_layer_ = FakeContentLayer::Create(&client_); |
| 432 copy_layer_->SetPosition(gfx::Point(15, 15)); |
| 433 copy_layer_->SetBounds(gfx::Size(10, 10)); |
| 434 parent_layer_->AddChild(copy_layer_); |
| 435 |
| 436 layer_tree_host()->SetRootLayer(root_); |
| 437 LayerTreeHostCopyRequestTest::SetupTree(); |
| 438 } |
| 439 |
| 440 virtual void BeginTest() OVERRIDE { |
| 441 PostSetNeedsCommitToMainThread(); |
| 442 |
| 443 copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( |
| 444 base::Bind(&LayerTreeHostCopyRequestTestClippedOut::CopyOutputCallback, |
| 445 base::Unretained(this)))); |
| 446 } |
| 447 |
| 448 void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { |
| 449 // We should still get a callback with no output if the copy requested layer |
| 450 // was completely clipped away. |
| 451 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); |
| 452 EXPECT_EQ(gfx::Size().ToString(), result->size().ToString()); |
| 453 EndTest(); |
| 454 } |
| 455 |
| 456 virtual void AfterTest() OVERRIDE {} |
| 457 |
| 458 FakeContentLayerClient client_; |
| 459 scoped_refptr<FakeContentLayer> root_; |
| 460 scoped_refptr<FakeContentLayer> parent_layer_; |
| 461 scoped_refptr<FakeContentLayer> copy_layer_; |
| 462 }; |
| 463 |
| 464 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( |
| 465 LayerTreeHostCopyRequestTestClippedOut); |
| 466 |
| 467 class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw |
| 468 : public LayerTreeHostCopyRequestTest { |
| 469 protected: |
| 470 virtual void SetupTree() OVERRIDE { |
| 471 root_ = FakeContentLayer::Create(&client_); |
| 472 root_->SetBounds(gfx::Size(20, 20)); |
| 473 |
| 474 copy_layer_ = FakeContentLayer::Create(&client_); |
| 475 copy_layer_->SetBounds(gfx::Size(10, 10)); |
| 476 root_->AddChild(copy_layer_); |
| 477 |
| 478 layer_tree_host()->SetRootLayer(root_); |
| 479 LayerTreeHostCopyRequestTest::SetupTree(); |
| 480 } |
| 481 |
| 482 void AddCopyRequest(Layer* layer) { |
| 483 layer->RequestCopyOfOutput( |
| 484 CopyOutputRequest::CreateBitmapRequest(base::Bind( |
| 485 &LayerTreeHostTestAsyncTwoReadbacksWithoutDraw::CopyOutputCallback, |
| 486 base::Unretained(this)))); |
| 487 } |
| 488 |
| 489 virtual void BeginTest() OVERRIDE { |
| 490 saw_copy_request_ = false; |
| 491 callback_count_ = 0; |
| 492 PostSetNeedsCommitToMainThread(); |
| 493 |
| 494 // Prevent drawing. |
| 495 layer_tree_host()->SetViewportSize(gfx::Size(0, 0)); |
| 496 |
| 497 AddCopyRequest(copy_layer_.get()); |
| 498 } |
| 499 |
| 500 virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE { |
| 501 if (impl->active_tree()->source_frame_number() == 0) { |
| 502 LayerImpl* root = impl->active_tree()->root_layer(); |
| 503 EXPECT_TRUE(root->children()[0]->HasCopyRequest()); |
| 504 saw_copy_request_ = true; |
| 505 } |
| 506 } |
| 507 |
| 508 virtual void DidCommit() OVERRIDE { |
| 509 if (layer_tree_host()->source_frame_number() == 1) { |
| 510 // Allow drawing. |
| 511 layer_tree_host()->SetViewportSize(gfx::Size(root_->bounds())); |
| 512 |
| 513 AddCopyRequest(copy_layer_.get()); |
| 514 } |
| 515 } |
| 516 |
| 517 void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { |
| 518 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); |
| 519 EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()); |
| 520 ++callback_count_; |
| 521 |
| 522 if (callback_count_ == 2) |
| 523 EndTest(); |
| 524 } |
| 525 |
| 526 virtual void AfterTest() OVERRIDE { EXPECT_TRUE(saw_copy_request_); } |
| 527 |
| 528 bool saw_copy_request_; |
| 529 int callback_count_; |
| 530 FakeContentLayerClient client_; |
| 531 scoped_refptr<FakeContentLayer> root_; |
| 532 scoped_refptr<FakeContentLayer> copy_layer_; |
| 533 }; |
| 534 |
| 535 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( |
| 536 LayerTreeHostTestAsyncTwoReadbacksWithoutDraw); |
| 537 |
| 538 class LayerTreeHostCopyRequestTestLostOutputSurface |
| 539 : public LayerTreeHostCopyRequestTest { |
| 540 protected: |
| 541 virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) |
| 542 OVERRIDE { |
| 543 if (!first_context_provider_.get()) { |
| 544 first_context_provider_ = TestContextProvider::Create(); |
| 545 return FakeOutputSurface::Create3d(first_context_provider_) |
| 546 .PassAs<OutputSurface>(); |
| 547 } |
| 548 |
| 549 EXPECT_FALSE(second_context_provider_.get()); |
| 550 second_context_provider_ = TestContextProvider::Create(); |
| 551 return FakeOutputSurface::Create3d(second_context_provider_) |
| 552 .PassAs<OutputSurface>(); |
| 553 } |
| 554 |
| 555 virtual void SetupTree() OVERRIDE { |
| 556 root_ = FakeContentLayer::Create(&client_); |
| 557 root_->SetBounds(gfx::Size(20, 20)); |
| 558 |
| 559 copy_layer_ = FakeContentLayer::Create(&client_); |
| 560 copy_layer_->SetBounds(gfx::Size(10, 10)); |
| 561 root_->AddChild(copy_layer_); |
| 562 |
| 563 layer_tree_host()->SetRootLayer(root_); |
| 564 LayerTreeHostCopyRequestTest::SetupTree(); |
| 565 } |
| 566 |
| 567 virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } |
| 568 |
| 569 void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { |
| 570 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); |
| 571 EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString()); |
| 572 EXPECT_TRUE(result->HasTexture()); |
| 573 |
| 574 // Save the result for later. |
| 575 EXPECT_FALSE(result_); |
| 576 result_ = result.Pass(); |
| 577 |
| 578 // Post a commit to lose the output surface. |
| 579 layer_tree_host()->SetNeedsCommit(); |
| 580 } |
| 581 |
| 582 virtual void DidCommitAndDrawFrame() OVERRIDE { |
| 583 switch (layer_tree_host()->source_frame_number()) { |
| 584 case 1: |
| 585 // The layers have been pushed to the impl side. The layer textures have |
| 586 // been allocated. |
| 587 |
| 588 // Request a copy of the layer. This will use another texture. |
| 589 copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateRequest( |
| 590 base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface:: |
| 591 CopyOutputCallback, |
| 592 base::Unretained(this)))); |
| 593 break; |
| 594 case 4: |
| 595 // With SingleThreadProxy it takes two commits to finally swap after a |
| 596 // context loss. |
| 597 case 5: |
| 598 // Now destroy the CopyOutputResult, releasing the texture inside back |
| 599 // to the compositor. |
| 600 EXPECT_TRUE(result_); |
| 601 result_.reset(); |
| 602 |
| 603 // Check that it is released. |
| 604 ImplThreadTaskRunner()->PostTask( |
| 605 FROM_HERE, |
| 606 base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface:: |
| 607 CheckNumTextures, |
| 608 base::Unretained(this), |
| 609 num_textures_after_loss_ - 1)); |
| 610 break; |
| 611 } |
| 612 } |
| 613 |
| 614 virtual void SwapBuffersOnThread(LayerTreeHostImpl* impl, |
| 615 bool result) OVERRIDE { |
| 616 switch (impl->active_tree()->source_frame_number()) { |
| 617 case 0: |
| 618 // The layers have been drawn, so their textures have been allocated. |
| 619 EXPECT_FALSE(result_); |
| 620 num_textures_without_readback_ = |
| 621 first_context_provider_->TestContext3d()->NumTextures(); |
| 622 break; |
| 623 case 1: |
| 624 // We did a readback, so there will be a readback texture around now. |
| 625 EXPECT_LT(num_textures_without_readback_, |
| 626 first_context_provider_->TestContext3d()->NumTextures()); |
| 627 break; |
| 628 case 2: |
| 629 // The readback texture is collected. |
| 630 EXPECT_TRUE(result_); |
| 631 |
| 632 // Lose the output surface. |
| 633 first_context_provider_->TestContext3d()->loseContextCHROMIUM( |
| 634 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); |
| 635 break; |
| 636 case 3: |
| 637 // With SingleThreadProxy it takes two commits to finally swap after a |
| 638 // context loss. |
| 639 case 4: |
| 640 // The output surface has been recreated. |
| 641 EXPECT_TRUE(second_context_provider_.get()); |
| 642 |
| 643 num_textures_after_loss_ = |
| 644 first_context_provider_->TestContext3d()->NumTextures(); |
| 645 break; |
| 646 } |
| 647 } |
| 648 |
| 649 void CheckNumTextures(size_t expected_num_textures) { |
| 650 EXPECT_EQ(expected_num_textures, |
| 651 first_context_provider_->TestContext3d()->NumTextures()); |
| 652 EndTest(); |
| 653 } |
| 654 |
| 655 virtual void AfterTest() OVERRIDE {} |
| 656 |
| 657 scoped_refptr<TestContextProvider> first_context_provider_; |
| 658 scoped_refptr<TestContextProvider> second_context_provider_; |
| 659 size_t num_textures_without_readback_; |
| 660 size_t num_textures_after_loss_; |
| 661 FakeContentLayerClient client_; |
| 662 scoped_refptr<FakeContentLayer> root_; |
| 663 scoped_refptr<FakeContentLayer> copy_layer_; |
| 664 scoped_ptr<CopyOutputResult> result_; |
| 665 }; |
| 666 |
| 667 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( |
| 668 LayerTreeHostCopyRequestTestLostOutputSurface); |
| 669 |
| 670 class LayerTreeHostCopyRequestTestCountTextures |
| 671 : public LayerTreeHostCopyRequestTest { |
| 672 protected: |
| 673 virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) |
| 674 OVERRIDE { |
| 675 context_provider_ = TestContextProvider::Create(); |
| 676 return FakeOutputSurface::Create3d(context_provider_) |
| 677 .PassAs<OutputSurface>(); |
| 678 } |
| 679 |
| 680 virtual void SetupTree() OVERRIDE { |
| 681 root_ = FakeContentLayer::Create(&client_); |
| 682 root_->SetBounds(gfx::Size(20, 20)); |
| 683 |
| 684 copy_layer_ = FakeContentLayer::Create(&client_); |
| 685 copy_layer_->SetBounds(gfx::Size(10, 10)); |
| 686 root_->AddChild(copy_layer_); |
| 687 |
| 688 layer_tree_host()->SetRootLayer(root_); |
| 689 LayerTreeHostCopyRequestTest::SetupTree(); |
| 690 } |
| 691 |
| 692 virtual void BeginTest() OVERRIDE { |
| 693 num_textures_without_readback_ = 0; |
| 694 num_textures_with_readback_ = 0; |
| 695 waited_sync_point_after_readback_ = 0; |
| 696 PostSetNeedsCommitToMainThread(); |
| 697 } |
| 698 |
| 699 virtual void RequestCopy(Layer* layer) = 0; |
| 700 |
| 701 virtual void DidCommitAndDrawFrame() OVERRIDE { |
| 702 switch (layer_tree_host()->source_frame_number()) { |
| 703 case 1: |
| 704 // The layers have been pushed to the impl side. The layer textures have |
| 705 // been allocated. |
| 706 RequestCopy(copy_layer_.get()); |
| 707 break; |
| 708 } |
| 709 } |
| 710 |
| 711 virtual void SwapBuffersOnThread(LayerTreeHostImpl* impl, |
| 712 bool result) OVERRIDE { |
| 713 switch (impl->active_tree()->source_frame_number()) { |
| 714 case 0: |
| 715 // The layers have been drawn, so their textures have been allocated. |
| 716 num_textures_without_readback_ = |
| 717 context_provider_->TestContext3d()->NumTextures(); |
| 718 break; |
| 719 case 1: |
| 720 // We did a readback, so there will be a readback texture around now. |
| 721 num_textures_with_readback_ = |
| 722 context_provider_->TestContext3d()->NumTextures(); |
| 723 waited_sync_point_after_readback_ = |
| 724 context_provider_->TestContext3d()->last_waited_sync_point(); |
| 725 |
| 726 MainThreadTaskRunner()->PostTask( |
| 727 FROM_HERE, |
| 728 base::Bind(&LayerTreeHostCopyRequestTestCountTextures::DoEndTest, |
| 729 base::Unretained(this))); |
| 730 break; |
| 731 } |
| 732 } |
| 733 |
| 734 virtual void DoEndTest() { EndTest(); } |
| 735 |
| 736 scoped_refptr<TestContextProvider> context_provider_; |
| 737 size_t num_textures_without_readback_; |
| 738 size_t num_textures_with_readback_; |
| 739 unsigned waited_sync_point_after_readback_; |
| 740 FakeContentLayerClient client_; |
| 741 scoped_refptr<FakeContentLayer> root_; |
| 742 scoped_refptr<FakeContentLayer> copy_layer_; |
| 743 }; |
| 744 |
| 745 class LayerTreeHostCopyRequestTestCreatesTexture |
| 746 : public LayerTreeHostCopyRequestTestCountTextures { |
| 747 protected: |
| 748 virtual void RequestCopy(Layer* layer) OVERRIDE { |
| 749 // Request a normal texture copy. This should create a new texture. |
| 750 copy_layer_->RequestCopyOfOutput( |
| 751 CopyOutputRequest::CreateRequest(base::Bind( |
| 752 &LayerTreeHostCopyRequestTestCreatesTexture::CopyOutputCallback, |
| 753 base::Unretained(this)))); |
| 754 } |
| 755 |
| 756 void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { |
| 757 EXPECT_FALSE(result->IsEmpty()); |
| 758 EXPECT_TRUE(result->HasTexture()); |
| 759 |
| 760 TextureMailbox mailbox; |
| 761 scoped_ptr<SingleReleaseCallback> release; |
| 762 result->TakeTexture(&mailbox, &release); |
| 763 EXPECT_TRUE(release); |
| 764 |
| 765 release->Run(0, false); |
| 766 } |
| 767 |
| 768 virtual void AfterTest() OVERRIDE { |
| 769 // No sync point was needed. |
| 770 EXPECT_EQ(0u, waited_sync_point_after_readback_); |
| 771 // Except the copy to have made another texture. |
| 772 EXPECT_EQ(num_textures_without_readback_ + 1, num_textures_with_readback_); |
| 773 } |
| 774 }; |
| 775 |
| 776 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( |
| 777 LayerTreeHostCopyRequestTestCreatesTexture); |
| 778 |
| 779 class LayerTreeHostCopyRequestTestProvideTexture |
| 780 : public LayerTreeHostCopyRequestTestCountTextures { |
| 781 protected: |
| 782 virtual void BeginTest() OVERRIDE { |
| 783 external_context_provider_ = TestContextProvider::Create(); |
| 784 EXPECT_TRUE(external_context_provider_->BindToCurrentThread()); |
| 785 LayerTreeHostCopyRequestTestCountTextures::BeginTest(); |
| 786 } |
| 787 |
| 788 void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { |
| 789 EXPECT_FALSE(result->IsEmpty()); |
| 790 EXPECT_TRUE(result->HasTexture()); |
| 791 |
| 792 TextureMailbox mailbox; |
| 793 scoped_ptr<SingleReleaseCallback> release; |
| 794 result->TakeTexture(&mailbox, &release); |
| 795 EXPECT_FALSE(release); |
| 796 } |
| 797 |
| 798 virtual void RequestCopy(Layer* layer) OVERRIDE { |
| 799 // Request a copy to a provided texture. This should not create a new |
| 800 // texture. |
| 801 scoped_ptr<CopyOutputRequest> request = |
| 802 CopyOutputRequest::CreateRequest(base::Bind( |
| 803 &LayerTreeHostCopyRequestTestProvideTexture::CopyOutputCallback, |
| 804 base::Unretained(this))); |
| 805 |
| 806 gpu::Mailbox mailbox; |
| 807 external_context_provider_->Context3d()->genMailboxCHROMIUM(mailbox.name); |
| 808 sync_point_ = external_context_provider_->Context3d()->insertSyncPoint(); |
| 809 request->SetTextureMailbox(TextureMailbox(mailbox, sync_point_)); |
| 810 EXPECT_TRUE(request->has_texture_mailbox()); |
| 811 |
| 812 copy_layer_->RequestCopyOfOutput(request.Pass()); |
| 813 } |
| 814 |
| 815 virtual void AfterTest() OVERRIDE { |
| 816 // Expect the compositor to have waited for the sync point in the provided |
| 817 // TextureMailbox. |
| 818 EXPECT_EQ(sync_point_, waited_sync_point_after_readback_); |
| 819 // Except the copy to have *not* made another texture. |
| 820 EXPECT_EQ(num_textures_without_readback_, num_textures_with_readback_); |
| 821 } |
| 822 |
| 823 scoped_refptr<TestContextProvider> external_context_provider_; |
| 824 unsigned sync_point_; |
| 825 }; |
| 826 |
| 827 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F( |
| 828 LayerTreeHostCopyRequestTestProvideTexture); |
| 829 |
| 830 } // namespace |
| 831 } // namespace cc |
OLD | NEW |