Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/compositor_impl_android.h" | 5 #include "content/browser/renderer_host/compositor_impl_android.h" |
| 6 | 6 |
| 7 #include <android/bitmap.h> | 7 #include <android/bitmap.h> |
| 8 #include <android/native_window_jni.h> | 8 #include <android/native_window_jni.h> |
| 9 | 9 |
| 10 #include "base/android/jni_android.h" | 10 #include "base/android/jni_android.h" |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 231 } | 231 } |
| 232 | 232 |
| 233 CompositorImpl::CompositorImpl(CompositorClient* client, | 233 CompositorImpl::CompositorImpl(CompositorClient* client, |
| 234 gfx::NativeWindow root_window) | 234 gfx::NativeWindow root_window) |
| 235 : root_layer_(cc::Layer::Create()), | 235 : root_layer_(cc::Layer::Create()), |
| 236 has_transparent_background_(false), | 236 has_transparent_background_(false), |
| 237 device_scale_factor_(1), | 237 device_scale_factor_(1), |
| 238 window_(NULL), | 238 window_(NULL), |
| 239 surface_id_(0), | 239 surface_id_(0), |
| 240 client_(client), | 240 client_(client), |
| 241 root_window_(root_window) { | 241 root_window_(root_window), |
| 242 did_post_swapbuffers_(false), | |
| 243 ignore_schedule_composite_(false), | |
| 244 needs_composite_(false), | |
| 245 should_composite_on_vsync_(false), | |
| 246 did_composite_this_frame_(false), | |
| 247 pending_swapbuffers_(0U), | |
| 248 weak_factory_(this) { | |
| 242 DCHECK(client); | 249 DCHECK(client); |
| 243 DCHECK(root_window); | 250 DCHECK(root_window); |
| 244 ImageTransportFactoryAndroid::AddObserver(this); | 251 ImageTransportFactoryAndroid::AddObserver(this); |
| 245 root_window->AttachCompositor(this); | 252 root_window->AttachCompositor(this); |
| 246 } | 253 } |
| 247 | 254 |
| 248 CompositorImpl::~CompositorImpl() { | 255 CompositorImpl::~CompositorImpl() { |
| 249 root_window_->DetachCompositor(); | 256 root_window_->DetachCompositor(); |
| 250 ImageTransportFactoryAndroid::RemoveObserver(this); | 257 ImageTransportFactoryAndroid::RemoveObserver(this); |
| 251 // Clean-up any surface references. | 258 // Clean-up any surface references. |
| 252 SetSurface(NULL); | 259 SetSurface(NULL); |
| 253 } | 260 } |
| 254 | 261 |
| 255 void CompositorImpl::Composite() { | 262 void CompositorImpl::PostComposite(base::TimeDelta delay) { |
| 256 if (host_) | 263 base::MessageLoop::current()->PostDelayedTask( |
| 257 host_->Composite(gfx::FrameTime::Now()); | 264 FROM_HERE, |
| 265 base::Bind(&CompositorImpl::Composite, | |
| 266 weak_factory_.GetWeakPtr(), | |
| 267 COMPOSITE_IMMEDIATELY), | |
| 268 delay); | |
| 269 } | |
| 270 | |
| 271 void CompositorImpl::Composite(CompositingTrigger trigger) { | |
| 272 if (!host_) | |
| 273 return; | |
| 274 | |
| 275 if (!needs_composite_) | |
| 276 return; | |
| 277 | |
| 278 if (trigger != COMPOSITE_ON_VSYNC && should_composite_on_vsync_) { | |
| 279 TRACE_EVENT0("compositor", "CompositorImpl_DeferCompositeToVSync"); | |
| 280 root_window_->RequestVSyncUpdate(); | |
| 281 return; | |
| 282 } | |
| 283 | |
| 284 // Don't Composite more than once in between vsync ticks. | |
| 285 if (did_composite_this_frame_) { | |
| 286 TRACE_EVENT0("compositor", "CompositorImpl_ThrottleComposite"); | |
| 287 if (should_composite_on_vsync_) | |
| 288 root_window_->RequestVSyncUpdate(); | |
| 289 else | |
| 290 PostComposite(vsync_period_); | |
|
brianderson
2014/05/10 00:24:40
Why PostComposite a vsync period away here instead
no sievers
2014/05/12 19:49:41
It would transition to vsync scheduling immediatel
| |
| 291 return; | |
| 292 } | |
| 293 | |
| 294 const unsigned int kMaxSwapBuffers = 2U; | |
| 295 DCHECK_LE(pending_swapbuffers_, kMaxSwapBuffers); | |
| 296 if (pending_swapbuffers_ == kMaxSwapBuffers) { | |
| 297 TRACE_EVENT0("compositor", "CompositorImpl_SwapLimit"); | |
| 298 if (should_composite_on_vsync_) | |
| 299 root_window_->RequestVSyncUpdate(); | |
| 300 else | |
| 301 PostComposite(vsync_period_); | |
| 302 return; | |
| 303 } | |
| 304 | |
| 305 // Reset state before Layout+Composite since that might create more | |
| 306 // requests to Composite that we need to respect. | |
| 307 needs_composite_ = false; | |
| 308 should_composite_on_vsync_ = false; | |
| 309 | |
| 310 // Ignore ScheduleComposite() from layer tree changes during Layout. | |
|
brianderson
2014/05/10 00:24:40
What happens if you don't ignore?
no sievers
2014/05/12 19:49:41
It would post a task to Composite() unnecessarily.
| |
| 311 ignore_schedule_composite_ = true; | |
| 312 client_->Layout(); | |
| 313 ignore_schedule_composite_ = false; | |
| 314 | |
| 315 did_post_swapbuffers_ = false; | |
| 316 host_->Composite(gfx::FrameTime::Now()); | |
| 317 if (did_post_swapbuffers_) | |
| 318 pending_swapbuffers_++; | |
| 319 | |
| 320 if (trigger != COMPOSITE_ON_VSYNC) { | |
| 321 // Need to track vsync to avoid compositing more than once per frame. | |
| 322 root_window_->RequestVSyncUpdate(); | |
| 323 } | |
| 324 did_composite_this_frame_ = true; | |
| 258 } | 325 } |
| 259 | 326 |
| 260 void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) { | 327 void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) { |
| 261 root_layer_->RemoveAllChildren(); | 328 root_layer_->RemoveAllChildren(); |
| 262 if (root_layer) | 329 if (root_layer) |
| 263 root_layer_->AddChild(root_layer); | 330 root_layer_->AddChild(root_layer); |
| 264 } | 331 } |
| 265 | 332 |
| 266 void CompositorImpl::SetWindowSurface(ANativeWindow* window) { | 333 void CompositorImpl::SetWindowSurface(ANativeWindow* window) { |
| 267 GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get(); | 334 GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get(); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 309 content::RegisterViewSurface(surface_id_, j_surface.obj()); | 376 content::RegisterViewSurface(surface_id_, j_surface.obj()); |
| 310 } | 377 } |
| 311 } | 378 } |
| 312 | 379 |
| 313 void CompositorImpl::SetVisible(bool visible) { | 380 void CompositorImpl::SetVisible(bool visible) { |
| 314 if (!visible) { | 381 if (!visible) { |
| 315 ui_resource_map_.clear(); | 382 ui_resource_map_.clear(); |
| 316 host_.reset(); | 383 host_.reset(); |
| 317 client_->UIResourcesAreInvalid(); | 384 client_->UIResourcesAreInvalid(); |
| 318 } else if (!host_) { | 385 } else if (!host_) { |
| 386 needs_composite_ = false; | |
| 387 did_composite_this_frame_ = false; | |
| 388 should_composite_on_vsync_ = false; | |
| 389 pending_swapbuffers_ = 0; | |
|
brianderson
2014/05/10 00:24:40
Do you not get pending acks when you go invisible?
no sievers
2014/05/12 19:49:41
Yes, I was running into accounting problems and it
| |
| 319 cc::LayerTreeSettings settings; | 390 cc::LayerTreeSettings settings; |
| 320 settings.refresh_rate = 60.0; | 391 settings.refresh_rate = 60.0; |
| 321 settings.impl_side_painting = false; | 392 settings.impl_side_painting = false; |
| 322 settings.allow_antialiasing = false; | 393 settings.allow_antialiasing = false; |
| 323 settings.calculate_top_controls_position = false; | 394 settings.calculate_top_controls_position = false; |
| 324 settings.top_controls_height = 0.f; | 395 settings.top_controls_height = 0.f; |
| 325 settings.highp_threshold_min = 2048; | 396 settings.highp_threshold_min = 2048; |
| 326 | 397 |
| 327 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 398 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 328 settings.initial_debug_state.SetRecordRenderingStats( | 399 settings.initial_debug_state.SetRecordRenderingStats( |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 367 host_->set_has_transparent_background(flag); | 438 host_->set_has_transparent_background(flag); |
| 368 } | 439 } |
| 369 | 440 |
| 370 bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) { | 441 bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) { |
| 371 if (host_) | 442 if (host_) |
| 372 return host_->CompositeAndReadback(pixels, rect); | 443 return host_->CompositeAndReadback(pixels, rect); |
| 373 else | 444 else |
| 374 return false; | 445 return false; |
| 375 } | 446 } |
| 376 | 447 |
| 448 void CompositorImpl::SetNeedsComposite() { | |
|
brianderson
2014/05/10 00:24:40
Is this the signal we get when the tab stack wants
no sievers
2014/05/12 19:49:41
Yea exactly. It's needed because we don't get a ca
| |
| 449 if (!host_.get() || needs_composite_) | |
| 450 return; | |
| 451 | |
| 452 needs_composite_ = true; | |
| 453 | |
| 454 // For explicit requests we try to composite regularly on vsync. | |
| 455 should_composite_on_vsync_ = true; | |
| 456 root_window_->RequestVSyncUpdate(); | |
| 457 } | |
| 458 | |
| 377 cc::UIResourceId CompositorImpl::GenerateUIResourceFromUIResourceBitmap( | 459 cc::UIResourceId CompositorImpl::GenerateUIResourceFromUIResourceBitmap( |
| 378 const cc::UIResourceBitmap& bitmap, | 460 const cc::UIResourceBitmap& bitmap, |
| 379 bool is_transient) { | 461 bool is_transient) { |
| 380 if (!host_) | 462 if (!host_) |
| 381 return 0; | 463 return 0; |
| 382 | 464 |
| 383 cc::UIResourceId id = 0; | 465 cc::UIResourceId id = 0; |
| 384 scoped_ptr<cc::UIResourceClient> resource; | 466 scoped_ptr<cc::UIResourceClient> resource; |
| 385 if (is_transient) { | 467 if (is_transient) { |
| 386 scoped_ptr<TransientUIResource> transient_resource = | 468 scoped_ptr<TransientUIResource> transient_resource = |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 461 return make_scoped_ptr( | 543 return make_scoped_ptr( |
| 462 new WebGraphicsContext3DCommandBufferImpl(surface_id, | 544 new WebGraphicsContext3DCommandBufferImpl(surface_id, |
| 463 url, | 545 url, |
| 464 gpu_channel_host.get(), | 546 gpu_channel_host.get(), |
| 465 attributes, | 547 attributes, |
| 466 lose_context_when_out_of_memory, | 548 lose_context_when_out_of_memory, |
| 467 limits, | 549 limits, |
| 468 NULL)); | 550 NULL)); |
| 469 } | 551 } |
| 470 | 552 |
| 553 void CompositorImpl::Layout() { | |
| 554 // TODO: If we get this callback from the SingleThreadProxy, we need | |
| 555 // to stop calling it ourselves in CompositorImpl::Composite(). | |
| 556 NOTREACHED(); | |
| 557 client_->Layout(); | |
| 558 } | |
| 559 | |
| 471 scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface( | 560 scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface( |
| 472 bool fallback) { | 561 bool fallback) { |
| 473 blink::WebGraphicsContext3D::Attributes attrs; | 562 blink::WebGraphicsContext3D::Attributes attrs; |
| 474 attrs.shareResources = true; | 563 attrs.shareResources = true; |
| 475 attrs.noAutomaticFlushes = true; | 564 attrs.noAutomaticFlushes = true; |
| 476 | 565 |
| 477 DCHECK(window_); | 566 DCHECK(window_); |
| 478 DCHECK(surface_id_); | 567 DCHECK(surface_id_); |
| 479 | 568 |
| 480 scoped_refptr<ContextProviderCommandBuffer> context_provider = | 569 scoped_refptr<ContextProviderCommandBuffer> context_provider = |
| 481 ContextProviderCommandBuffer::Create( | 570 ContextProviderCommandBuffer::Create( |
| 482 CreateGpuProcessViewContext(attrs, surface_id_), "BrowserCompositor"); | 571 CreateGpuProcessViewContext(attrs, surface_id_), "BrowserCompositor"); |
| 483 if (!context_provider.get()) { | 572 if (!context_provider.get()) { |
| 484 LOG(ERROR) << "Failed to create 3D context for compositor."; | 573 LOG(ERROR) << "Failed to create 3D context for compositor."; |
| 485 return scoped_ptr<cc::OutputSurface>(); | 574 return scoped_ptr<cc::OutputSurface>(); |
| 486 } | 575 } |
| 487 | 576 |
| 488 return scoped_ptr<cc::OutputSurface>( | 577 return scoped_ptr<cc::OutputSurface>( |
| 489 new OutputSurfaceWithoutParent(context_provider)); | 578 new OutputSurfaceWithoutParent(context_provider)); |
| 490 } | 579 } |
| 491 | 580 |
| 492 void CompositorImpl::OnLostResources() { | 581 void CompositorImpl::OnLostResources() { |
| 493 client_->DidLoseResources(); | 582 client_->DidLoseResources(); |
| 494 } | 583 } |
| 495 | 584 |
| 496 void CompositorImpl::DidCompleteSwapBuffers() { | 585 void CompositorImpl::ScheduleComposite() { |
| 497 client_->OnSwapBuffersCompleted(); | 586 if (needs_composite_ || ignore_schedule_composite_) |
| 498 } | 587 return; |
| 499 | 588 |
| 500 void CompositorImpl::ScheduleComposite() { | 589 needs_composite_ = true; |
| 501 client_->ScheduleComposite(); | 590 |
| 591 // We currently expect layer tree invalidations at most once per frame | |
| 592 // during normal operation and therefore try to composite immediately | |
| 593 // to minimize latency. | |
| 594 PostComposite(base::TimeDelta()); | |
| 502 } | 595 } |
| 503 | 596 |
| 504 void CompositorImpl::ScheduleAnimation() { | 597 void CompositorImpl::ScheduleAnimation() { |
| 505 ScheduleComposite(); | 598 ScheduleComposite(); |
| 506 } | 599 } |
| 507 | 600 |
| 508 void CompositorImpl::DidPostSwapBuffers() { | 601 void CompositorImpl::DidPostSwapBuffers() { |
| 509 TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers"); | 602 TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers"); |
| 510 client_->OnSwapBuffersPosted(); | 603 did_post_swapbuffers_ = true; |
| 604 } | |
| 605 | |
| 606 void CompositorImpl::DidCompleteSwapBuffers() { | |
| 607 TRACE_EVENT0("compositor", "CompositorImpl::DidCompleteSwapBuffers"); | |
| 608 DCHECK_GT(pending_swapbuffers_, 0U); | |
| 609 client_->OnSwapBuffersCompleted(pending_swapbuffers_--); | |
|
brianderson
2014/05/10 00:24:40
Can you decrement after the function call?
no sievers
2014/05/12 19:49:41
Isn't that the same?
| |
| 511 } | 610 } |
| 512 | 611 |
| 513 void CompositorImpl::DidAbortSwapBuffers() { | 612 void CompositorImpl::DidAbortSwapBuffers() { |
| 514 TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers"); | 613 TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers"); |
| 515 client_->OnSwapBuffersCompleted(); | 614 DCHECK_GT(pending_swapbuffers_, 0U); |
| 615 client_->OnSwapBuffersCompleted(pending_swapbuffers_--); | |
| 516 } | 616 } |
| 517 | 617 |
| 518 void CompositorImpl::DidCommit() { | 618 void CompositorImpl::DidCommit() { |
| 519 root_window_->OnCompositingDidCommit(); | 619 root_window_->OnCompositingDidCommit(); |
| 520 } | 620 } |
| 521 | 621 |
| 522 void CompositorImpl::AttachLayerForReadback(scoped_refptr<cc::Layer> layer) { | 622 void CompositorImpl::AttachLayerForReadback(scoped_refptr<cc::Layer> layer) { |
| 523 root_layer_->AddChild(layer); | 623 root_layer_->AddChild(layer); |
| 524 } | 624 } |
| 525 | 625 |
| 626 void CompositorImpl::OnVSync(base::TimeTicks frame_time, | |
| 627 base::TimeDelta vsync_period) { | |
| 628 vsync_period_ = vsync_period; | |
| 629 did_composite_this_frame_ = false; | |
| 630 | |
| 631 if (should_composite_on_vsync_) | |
| 632 Composite(COMPOSITE_ON_VSYNC); | |
| 633 } | |
| 634 | |
| 526 } // namespace content | 635 } // namespace content |
| OLD | NEW |