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