| 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 "ui/compositor/compositor.h" | 5 #include "ui/compositor/compositor.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <deque> | 8 #include <deque> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 namespace { | 43 namespace { |
| 44 | 44 |
| 45 const double kDefaultRefreshRate = 60.0; | 45 const double kDefaultRefreshRate = 60.0; |
| 46 const double kTestRefreshRate = 200.0; | 46 const double kTestRefreshRate = 200.0; |
| 47 | 47 |
| 48 enum SwapType { | 48 enum SwapType { |
| 49 DRAW_SWAP, | 49 DRAW_SWAP, |
| 50 READPIXELS_SWAP, | 50 READPIXELS_SWAP, |
| 51 }; | 51 }; |
| 52 | 52 |
| 53 bool g_compositor_initialized = false; | |
| 54 base::Thread* g_compositor_thread = NULL; | 53 base::Thread* g_compositor_thread = NULL; |
| 55 | 54 |
| 55 bool g_test_compositor_enabled = false; |
| 56 |
| 56 ui::ContextFactory* g_implicit_factory = NULL; | 57 ui::ContextFactory* g_implicit_factory = NULL; |
| 57 ui::ContextFactory* g_context_factory = NULL; | 58 ui::ContextFactory* g_context_factory = NULL; |
| 58 | 59 |
| 59 const int kCompositorLockTimeoutMs = 67; | 60 const int kCompositorLockTimeoutMs = 67; |
| 60 | 61 |
| 61 class PendingSwap { | 62 class PendingSwap { |
| 62 public: | 63 public: |
| 63 PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps); | 64 PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps); |
| 64 ~PendingSwap(); | 65 ~PendingSwap(); |
| 65 | 66 |
| 66 SwapType type() const { return type_; } | 67 SwapType type() const { return type_; } |
| 67 bool posted() const { return posted_; } | 68 bool posted() const { return posted_; } |
| 68 | 69 |
| 69 private: | 70 private: |
| 70 friend class ui::PostedSwapQueue; | 71 friend class ui::PostedSwapQueue; |
| 71 | 72 |
| 72 SwapType type_; | 73 SwapType type_; |
| 73 bool posted_; | 74 bool posted_; |
| 74 ui::PostedSwapQueue* posted_swaps_; | 75 ui::PostedSwapQueue* posted_swaps_; |
| 75 | 76 |
| 76 DISALLOW_COPY_AND_ASSIGN(PendingSwap); | 77 DISALLOW_COPY_AND_ASSIGN(PendingSwap); |
| 77 }; | 78 }; |
| 78 | 79 |
| 80 void SetupImplicitFactory() { |
| 81 // We leak the implicit factory so that we don't race with the tear down of |
| 82 // the gl_bindings. |
| 83 DCHECK(!g_context_factory); |
| 84 DCHECK(!g_implicit_factory); |
| 85 if (g_test_compositor_enabled) { |
| 86 g_implicit_factory = new ui::TestContextFactory; |
| 87 } else { |
| 88 DVLOG(1) << "Using DefaultContextFactory"; |
| 89 scoped_ptr<ui::DefaultContextFactory> instance( |
| 90 new ui::DefaultContextFactory()); |
| 91 if (instance->Initialize()) |
| 92 g_implicit_factory = instance.release(); |
| 93 } |
| 94 g_context_factory = g_implicit_factory; |
| 95 } |
| 96 |
| 97 void ResetImplicitFactory() { |
| 98 if (!g_implicit_factory || g_context_factory != g_implicit_factory) |
| 99 return; |
| 100 delete g_implicit_factory; |
| 101 g_implicit_factory = NULL; |
| 102 g_context_factory = NULL; |
| 103 } |
| 104 |
| 79 } // namespace | 105 } // namespace |
| 80 | 106 |
| 81 namespace ui { | 107 namespace ui { |
| 82 | 108 |
| 83 // static | 109 // static |
| 84 ContextFactory* ContextFactory::GetInstance() { | 110 ContextFactory* ContextFactory::GetInstance() { |
| 85 DCHECK(g_context_factory); | 111 if (!g_context_factory) |
| 112 SetupImplicitFactory(); |
| 86 return g_context_factory; | 113 return g_context_factory; |
| 87 } | 114 } |
| 88 | 115 |
| 89 // static | 116 // static |
| 90 void ContextFactory::SetInstance(ContextFactory* instance) { | 117 void ContextFactory::SetInstance(ContextFactory* instance) { |
| 91 g_context_factory = instance; | 118 g_context_factory = instance; |
| 92 } | 119 } |
| 93 | 120 |
| 94 DefaultContextFactory::DefaultContextFactory() { | 121 DefaultContextFactory::DefaultContextFactory() { |
| 95 } | 122 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 !offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) { | 173 !offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) { |
| 147 offscreen_contexts_compositor_thread_ = | 174 offscreen_contexts_compositor_thread_ = |
| 148 ContextProviderFromContextFactory::CreateForOffscreen(this); | 175 ContextProviderFromContextFactory::CreateForOffscreen(this); |
| 149 } | 176 } |
| 150 return offscreen_contexts_compositor_thread_; | 177 return offscreen_contexts_compositor_thread_; |
| 151 } | 178 } |
| 152 | 179 |
| 153 void DefaultContextFactory::RemoveCompositor(Compositor* compositor) { | 180 void DefaultContextFactory::RemoveCompositor(Compositor* compositor) { |
| 154 } | 181 } |
| 155 | 182 |
| 156 bool DefaultContextFactory::DoesCreateTestContexts() { return false; } | |
| 157 | |
| 158 scoped_ptr<WebKit::WebGraphicsContext3D> | 183 scoped_ptr<WebKit::WebGraphicsContext3D> |
| 159 DefaultContextFactory::CreateContextCommon(Compositor* compositor, | 184 DefaultContextFactory::CreateContextCommon(Compositor* compositor, |
| 160 bool offscreen) { | 185 bool offscreen) { |
| 161 DCHECK(offscreen || compositor); | 186 DCHECK(offscreen || compositor); |
| 162 WebKit::WebGraphicsContext3D::Attributes attrs; | 187 WebKit::WebGraphicsContext3D::Attributes attrs; |
| 163 attrs.depth = false; | 188 attrs.depth = false; |
| 164 attrs.stencil = false; | 189 attrs.stencil = false; |
| 165 attrs.antialias = false; | 190 attrs.antialias = false; |
| 166 attrs.shareResources = true; | 191 attrs.shareResources = true; |
| 167 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; | 192 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) { | 241 offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) { |
| 217 offscreen_contexts_compositor_thread_ = | 242 offscreen_contexts_compositor_thread_ = |
| 218 ContextProviderFromContextFactory::CreateForOffscreen(this); | 243 ContextProviderFromContextFactory::CreateForOffscreen(this); |
| 219 } | 244 } |
| 220 return offscreen_contexts_compositor_thread_; | 245 return offscreen_contexts_compositor_thread_; |
| 221 } | 246 } |
| 222 | 247 |
| 223 void TestContextFactory::RemoveCompositor(Compositor* compositor) { | 248 void TestContextFactory::RemoveCompositor(Compositor* compositor) { |
| 224 } | 249 } |
| 225 | 250 |
| 226 bool TestContextFactory::DoesCreateTestContexts() { return true; } | |
| 227 | |
| 228 Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor) | 251 Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor) |
| 229 : size_(size), | 252 : size_(size), |
| 230 flipped_(flipped), | 253 flipped_(flipped), |
| 231 device_scale_factor_(device_scale_factor) { | 254 device_scale_factor_(device_scale_factor) { |
| 232 } | 255 } |
| 233 | 256 |
| 234 Texture::~Texture() { | 257 Texture::~Texture() { |
| 235 } | 258 } |
| 236 | 259 |
| 237 std::string Texture::Produce() { | 260 std::string Texture::Produce() { |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 : delegate_(delegate), | 403 : delegate_(delegate), |
| 381 root_layer_(NULL), | 404 root_layer_(NULL), |
| 382 widget_(widget), | 405 widget_(widget), |
| 383 posted_swaps_(new PostedSwapQueue()), | 406 posted_swaps_(new PostedSwapQueue()), |
| 384 device_scale_factor_(0.0f), | 407 device_scale_factor_(0.0f), |
| 385 last_started_frame_(0), | 408 last_started_frame_(0), |
| 386 last_ended_frame_(0), | 409 last_ended_frame_(0), |
| 387 next_draw_is_resize_(false), | 410 next_draw_is_resize_(false), |
| 388 disable_schedule_composite_(false), | 411 disable_schedule_composite_(false), |
| 389 compositor_lock_(NULL) { | 412 compositor_lock_(NULL) { |
| 390 DCHECK(g_compositor_initialized) | |
| 391 << "Compositor::Initialize must be called before creating a Compositor."; | |
| 392 | |
| 393 root_web_layer_ = cc::Layer::Create(); | 413 root_web_layer_ = cc::Layer::Create(); |
| 394 root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f)); | 414 root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f)); |
| 395 | 415 |
| 396 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 416 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 397 | 417 |
| 398 cc::LayerTreeSettings settings; | 418 cc::LayerTreeSettings settings; |
| 399 settings.refresh_rate = | 419 settings.refresh_rate = |
| 400 ContextFactory::GetInstance()->DoesCreateTestContexts() | 420 g_test_compositor_enabled ? kTestRefreshRate : kDefaultRefreshRate; |
| 401 ? kTestRefreshRate | |
| 402 : kDefaultRefreshRate; | |
| 403 settings.partial_swap_enabled = | 421 settings.partial_swap_enabled = |
| 404 !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap); | 422 !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap); |
| 405 settings.per_tile_painting_enabled = | 423 settings.per_tile_painting_enabled = |
| 406 command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting); | 424 command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting); |
| 407 | 425 |
| 408 // These flags should be mirrored by renderer versions in content/renderer/. | 426 // These flags should be mirrored by renderer versions in content/renderer/. |
| 409 settings.initial_debug_state.show_debug_borders = | 427 settings.initial_debug_state.show_debug_borders = |
| 410 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders); | 428 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders); |
| 411 settings.initial_debug_state.show_fps_counter = | 429 settings.initial_debug_state.show_fps_counter = |
| 412 command_line->HasSwitch(cc::switches::kUIShowFPSCounter); | 430 command_line->HasSwitch(cc::switches::kUIShowFPSCounter); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 427 | 445 |
| 428 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner = | 446 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner = |
| 429 g_compositor_thread ? g_compositor_thread->message_loop_proxy() : NULL; | 447 g_compositor_thread ? g_compositor_thread->message_loop_proxy() : NULL; |
| 430 | 448 |
| 431 host_ = cc::LayerTreeHost::Create(this, settings, compositor_task_runner); | 449 host_ = cc::LayerTreeHost::Create(this, settings, compositor_task_runner); |
| 432 host_->SetRootLayer(root_web_layer_); | 450 host_->SetRootLayer(root_web_layer_); |
| 433 host_->SetLayerTreeHostClientReady(); | 451 host_->SetLayerTreeHostClientReady(); |
| 434 } | 452 } |
| 435 | 453 |
| 436 Compositor::~Compositor() { | 454 Compositor::~Compositor() { |
| 437 DCHECK(g_compositor_initialized); | |
| 438 | |
| 439 CancelCompositorLock(); | 455 CancelCompositorLock(); |
| 440 DCHECK(!compositor_lock_); | 456 DCHECK(!compositor_lock_); |
| 441 | 457 |
| 442 // Don't call |CompositorDelegate::ScheduleDraw| from this point. | 458 // Don't call |CompositorDelegate::ScheduleDraw| from this point. |
| 443 delegate_ = NULL; | 459 delegate_ = NULL; |
| 444 if (root_layer_) | 460 if (root_layer_) |
| 445 root_layer_->SetCompositor(NULL); | 461 root_layer_->SetCompositor(NULL); |
| 446 | 462 |
| 447 // Stop all outstanding draws before telling the ContextFactory to tear | 463 // Stop all outstanding draws before telling the ContextFactory to tear |
| 448 // down any contexts that the |host_| may rely upon. | 464 // down any contexts that the |host_| may rely upon. |
| 449 host_.reset(); | 465 host_.reset(); |
| 450 | 466 |
| 451 ContextFactory::GetInstance()->RemoveCompositor(this); | 467 ContextFactory::GetInstance()->RemoveCompositor(this); |
| 452 } | 468 } |
| 453 | 469 |
| 454 // static | 470 // static |
| 455 void Compositor::InitializeContextFactoryForTests(bool allow_test_contexts) { | |
| 456 DCHECK(!g_context_factory) << "ContextFactory already initialized."; | |
| 457 DCHECK(!g_implicit_factory) << | |
| 458 "ContextFactory for tests already initialized."; | |
| 459 | |
| 460 bool use_test_contexts = true; | |
| 461 | |
| 462 // Always use test contexts unless the disable command line flag is used. | |
| 463 CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
| 464 if (command_line->HasSwitch(switches::kDisableTestCompositor)) | |
| 465 use_test_contexts = false; | |
| 466 | |
| 467 #if defined(OS_CHROMEOS) | |
| 468 // If the test is running on the chromeos envrionment (such as | |
| 469 // device or vm bots), always use real contexts. | |
| 470 if (base::chromeos::IsRunningOnChromeOS()) | |
| 471 use_test_contexts = false; | |
| 472 #endif | |
| 473 | |
| 474 if (!allow_test_contexts) | |
| 475 use_test_contexts = false; | |
| 476 | |
| 477 if (use_test_contexts) { | |
| 478 g_implicit_factory = new ui::TestContextFactory; | |
| 479 } else { | |
| 480 DVLOG(1) << "Using DefaultContextFactory"; | |
| 481 scoped_ptr<ui::DefaultContextFactory> instance( | |
| 482 new ui::DefaultContextFactory()); | |
| 483 if (instance->Initialize()) | |
| 484 g_implicit_factory = instance.release(); | |
| 485 } | |
| 486 g_context_factory = g_implicit_factory; | |
| 487 } | |
| 488 | |
| 489 // static | |
| 490 void Compositor::Initialize() { | 471 void Compositor::Initialize() { |
| 491 #if defined(OS_CHROMEOS) | 472 #if defined(OS_CHROMEOS) |
| 492 bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch( | 473 bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch( |
| 493 switches::kUIDisableThreadedCompositing); | 474 switches::kUIDisableThreadedCompositing); |
| 494 #else | 475 #else |
| 495 bool use_thread = | 476 bool use_thread = |
| 496 CommandLine::ForCurrentProcess()->HasSwitch( | 477 CommandLine::ForCurrentProcess()->HasSwitch( |
| 497 switches::kUIEnableThreadedCompositing) && | 478 switches::kUIEnableThreadedCompositing) && |
| 498 !CommandLine::ForCurrentProcess()->HasSwitch( | 479 !CommandLine::ForCurrentProcess()->HasSwitch( |
| 499 switches::kUIDisableThreadedCompositing); | 480 switches::kUIDisableThreadedCompositing); |
| 500 #endif | 481 #endif |
| 501 if (use_thread) { | 482 if (use_thread) { |
| 502 g_compositor_thread = new base::Thread("Browser Compositor"); | 483 g_compositor_thread = new base::Thread("Browser Compositor"); |
| 503 g_compositor_thread->Start(); | 484 g_compositor_thread->Start(); |
| 504 } | 485 } |
| 505 | |
| 506 DCHECK(!g_compositor_initialized) << "Compositor initialized twice."; | |
| 507 g_compositor_initialized = true; | |
| 508 } | 486 } |
| 509 | 487 |
| 510 // static | 488 // static |
| 511 bool Compositor::WasInitializedWithThread() { | 489 bool Compositor::WasInitializedWithThread() { |
| 512 return !!g_compositor_thread; | 490 return !!g_compositor_thread; |
| 513 } | 491 } |
| 514 | 492 |
| 515 // static | 493 // static |
| 516 scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() { | 494 scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() { |
| 517 scoped_refptr<base::MessageLoopProxy> proxy; | 495 scoped_refptr<base::MessageLoopProxy> proxy; |
| 518 if (g_compositor_thread) | 496 if (g_compositor_thread) |
| 519 proxy = g_compositor_thread->message_loop_proxy(); | 497 proxy = g_compositor_thread->message_loop_proxy(); |
| 520 return proxy; | 498 return proxy; |
| 521 } | 499 } |
| 522 | 500 |
| 523 // static | 501 // static |
| 524 void Compositor::Terminate() { | 502 void Compositor::Terminate() { |
| 525 if (g_context_factory) { | |
| 526 if (g_implicit_factory) { | |
| 527 delete g_implicit_factory; | |
| 528 g_implicit_factory = NULL; | |
| 529 } | |
| 530 g_context_factory = NULL; | |
| 531 } | |
| 532 | |
| 533 if (g_compositor_thread) { | 503 if (g_compositor_thread) { |
| 534 DCHECK(!g_context_factory) | |
| 535 << "The ContextFactory should not outlive the compositor thread."; | |
| 536 g_compositor_thread->Stop(); | 504 g_compositor_thread->Stop(); |
| 537 delete g_compositor_thread; | 505 delete g_compositor_thread; |
| 538 g_compositor_thread = NULL; | 506 g_compositor_thread = NULL; |
| 539 } | 507 } |
| 540 | |
| 541 DCHECK(g_compositor_initialized) << "Compositor::Initialize() didn't happen."; | |
| 542 g_compositor_initialized = false; | |
| 543 } | 508 } |
| 544 | 509 |
| 545 void Compositor::ScheduleDraw() { | 510 void Compositor::ScheduleDraw() { |
| 546 if (g_compositor_thread) | 511 if (g_compositor_thread) |
| 547 host_->Composite(base::TimeTicks::Now()); | 512 host_->Composite(base::TimeTicks::Now()); |
| 548 else if (delegate_) | 513 else if (delegate_) |
| 549 delegate_->ScheduleDraw(); | 514 delegate_->ScheduleDraw(); |
| 550 } | 515 } |
| 551 | 516 |
| 552 void Compositor::SetRootLayer(Layer* root_layer) { | 517 void Compositor::SetRootLayer(Layer* root_layer) { |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 779 compositor_lock_->CancelLock(); | 744 compositor_lock_->CancelLock(); |
| 780 } | 745 } |
| 781 | 746 |
| 782 void Compositor::NotifyEnd() { | 747 void Compositor::NotifyEnd() { |
| 783 last_ended_frame_++; | 748 last_ended_frame_++; |
| 784 FOR_EACH_OBSERVER(CompositorObserver, | 749 FOR_EACH_OBSERVER(CompositorObserver, |
| 785 observer_list_, | 750 observer_list_, |
| 786 OnCompositingEnded(this)); | 751 OnCompositingEnded(this)); |
| 787 } | 752 } |
| 788 | 753 |
| 754 COMPOSITOR_EXPORT void SetupTestCompositor() { |
| 755 if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| 756 switches::kDisableTestCompositor)) { |
| 757 g_test_compositor_enabled = true; |
| 758 } |
| 759 #if defined(OS_CHROMEOS) |
| 760 // If the test is running on the chromeos envrionment (such as |
| 761 // device or vm bots), use the real compositor. |
| 762 if (base::chromeos::IsRunningOnChromeOS()) |
| 763 g_test_compositor_enabled = false; |
| 764 #endif |
| 765 ResetImplicitFactory(); |
| 766 } |
| 767 |
| 768 COMPOSITOR_EXPORT void DisableTestCompositor() { |
| 769 ResetImplicitFactory(); |
| 770 g_test_compositor_enabled = false; |
| 771 } |
| 772 |
| 773 COMPOSITOR_EXPORT bool IsTestCompositorEnabled() { |
| 774 return g_test_compositor_enabled; |
| 775 } |
| 776 |
| 789 } // namespace ui | 777 } // namespace ui |
| OLD | NEW |