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 |