Correct blacklist entry message
[chromium-blink-merge.git] / ui / compositor / compositor.cc
blob1061424c06a126fe7c552b17470b5d110ff57640
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
3 // found in the LICENSE file.
5 #include "ui/compositor/compositor.h"
7 #include <algorithm>
8 #include <deque>
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/debug/trace_event.h"
13 #include "base/memory/singleton.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string_util.h"
17 #include "base/sys_info.h"
18 #include "base/threading/thread.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "cc/base/switches.h"
21 #include "cc/input/input_handler.h"
22 #include "cc/layers/layer.h"
23 #include "cc/output/context_provider.h"
24 #include "cc/trees/layer_tree_host.h"
25 #include "third_party/skia/include/core/SkBitmap.h"
26 #include "ui/compositor/compositor_observer.h"
27 #include "ui/compositor/compositor_switches.h"
28 #include "ui/compositor/dip_util.h"
29 #include "ui/compositor/layer.h"
30 #include "ui/gfx/frame_time.h"
31 #include "ui/gl/gl_context.h"
32 #include "ui/gl/gl_switches.h"
34 namespace {
36 const double kDefaultRefreshRate = 60.0;
37 const double kTestRefreshRate = 200.0;
39 enum SwapType {
40 DRAW_SWAP,
41 READPIXELS_SWAP,
44 bool g_compositor_initialized = false;
45 base::Thread* g_compositor_thread = NULL;
47 ui::ContextFactory* g_context_factory = NULL;
49 const int kCompositorLockTimeoutMs = 67;
51 class PendingSwap {
52 public:
53 PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps);
54 ~PendingSwap();
56 SwapType type() const { return type_; }
57 bool posted() const { return posted_; }
59 private:
60 friend class ui::PostedSwapQueue;
62 SwapType type_;
63 bool posted_;
64 ui::PostedSwapQueue* posted_swaps_;
66 DISALLOW_COPY_AND_ASSIGN(PendingSwap);
69 } // namespace
71 namespace ui {
73 // static
74 ContextFactory* ContextFactory::GetInstance() {
75 DCHECK(g_context_factory);
76 return g_context_factory;
79 // static
80 void ContextFactory::SetInstance(ContextFactory* instance) {
81 g_context_factory = instance;
84 Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor)
85 : size_(size),
86 flipped_(flipped),
87 device_scale_factor_(device_scale_factor) {
90 Texture::~Texture() {
93 std::string Texture::Produce() {
94 return EmptyString();
97 CompositorLock::CompositorLock(Compositor* compositor)
98 : compositor_(compositor) {
99 base::MessageLoop::current()->PostDelayedTask(
100 FROM_HERE,
101 base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
102 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
105 CompositorLock::~CompositorLock() {
106 CancelLock();
109 void CompositorLock::CancelLock() {
110 if (!compositor_)
111 return;
112 compositor_->UnlockCompositor();
113 compositor_ = NULL;
116 // static
117 void DrawWaiterForTest::Wait(Compositor* compositor) {
118 DrawWaiterForTest waiter;
119 waiter.wait_for_commit_ = false;
120 waiter.WaitImpl(compositor);
123 // static
124 void DrawWaiterForTest::WaitForCommit(Compositor* compositor) {
125 DrawWaiterForTest waiter;
126 waiter.wait_for_commit_ = true;
127 waiter.WaitImpl(compositor);
130 DrawWaiterForTest::DrawWaiterForTest() {
133 DrawWaiterForTest::~DrawWaiterForTest() {
136 void DrawWaiterForTest::WaitImpl(Compositor* compositor) {
137 compositor->AddObserver(this);
138 wait_run_loop_.reset(new base::RunLoop());
139 wait_run_loop_->Run();
140 compositor->RemoveObserver(this);
143 void DrawWaiterForTest::OnCompositingDidCommit(Compositor* compositor) {
144 if (wait_for_commit_)
145 wait_run_loop_->Quit();
148 void DrawWaiterForTest::OnCompositingStarted(Compositor* compositor,
149 base::TimeTicks start_time) {
152 void DrawWaiterForTest::OnCompositingEnded(Compositor* compositor) {
153 if (!wait_for_commit_)
154 wait_run_loop_->Quit();
157 void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) {
160 void DrawWaiterForTest::OnCompositingLockStateChanged(Compositor* compositor) {
163 void DrawWaiterForTest::OnUpdateVSyncParameters(Compositor* compositor,
164 base::TimeTicks timebase,
165 base::TimeDelta interval) {
168 class PostedSwapQueue {
169 public:
170 PostedSwapQueue() : pending_swap_(NULL) {
173 ~PostedSwapQueue() {
174 DCHECK(!pending_swap_);
177 SwapType NextPostedSwap() const {
178 return queue_.front();
181 bool AreSwapsPosted() const {
182 return !queue_.empty();
185 int NumSwapsPosted(SwapType type) const {
186 int count = 0;
187 for (std::deque<SwapType>::const_iterator it = queue_.begin();
188 it != queue_.end(); ++it) {
189 if (*it == type)
190 count++;
192 return count;
195 void PostSwap() {
196 DCHECK(pending_swap_);
197 queue_.push_back(pending_swap_->type());
198 pending_swap_->posted_ = true;
201 void EndSwap() {
202 queue_.pop_front();
205 private:
206 friend class ::PendingSwap;
208 PendingSwap* pending_swap_;
209 std::deque<SwapType> queue_;
211 DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue);
214 } // namespace ui
216 namespace {
218 PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps)
219 : type_(type), posted_(false), posted_swaps_(posted_swaps) {
220 // Only one pending swap in flight.
221 DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_);
222 posted_swaps_->pending_swap_ = this;
225 PendingSwap::~PendingSwap() {
226 DCHECK_EQ(this, posted_swaps_->pending_swap_);
227 posted_swaps_->pending_swap_ = NULL;
230 } // namespace
232 namespace ui {
234 Compositor::Compositor(gfx::AcceleratedWidget widget)
235 : root_layer_(NULL),
236 widget_(widget),
237 posted_swaps_(new PostedSwapQueue()),
238 device_scale_factor_(0.0f),
239 last_started_frame_(0),
240 last_ended_frame_(0),
241 next_draw_is_resize_(false),
242 disable_schedule_composite_(false),
243 compositor_lock_(NULL),
244 defer_draw_scheduling_(false),
245 waiting_on_compositing_end_(false),
246 draw_on_compositing_end_(false),
247 schedule_draw_factory_(this) {
248 DCHECK(g_compositor_initialized)
249 << "Compositor::Initialize must be called before creating a Compositor.";
251 root_web_layer_ = cc::Layer::Create();
252 root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
254 CommandLine* command_line = CommandLine::ForCurrentProcess();
256 cc::LayerTreeSettings settings;
257 settings.refresh_rate =
258 ContextFactory::GetInstance()->DoesCreateTestContexts()
259 ? kTestRefreshRate
260 : kDefaultRefreshRate;
261 settings.deadline_scheduling_enabled =
262 switches::IsUIDeadlineSchedulingEnabled();
263 settings.partial_swap_enabled =
264 !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap);
265 settings.per_tile_painting_enabled =
266 command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting);
268 // These flags should be mirrored by renderer versions in content/renderer/.
269 settings.initial_debug_state.show_debug_borders =
270 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders);
271 settings.initial_debug_state.show_fps_counter =
272 command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
273 settings.initial_debug_state.show_paint_rects =
274 command_line->HasSwitch(switches::kUIShowPaintRects);
275 settings.initial_debug_state.show_property_changed_rects =
276 command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects);
277 settings.initial_debug_state.show_surface_damage_rects =
278 command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects);
279 settings.initial_debug_state.show_screen_space_rects =
280 command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects);
281 settings.initial_debug_state.show_replica_screen_space_rects =
282 command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects);
283 settings.initial_debug_state.show_occluding_rects =
284 command_line->HasSwitch(cc::switches::kUIShowOccludingRects);
285 settings.initial_debug_state.show_non_occluding_rects =
286 command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
288 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner =
289 g_compositor_thread ? g_compositor_thread->message_loop_proxy() : NULL;
291 host_ =
292 cc::LayerTreeHost::Create(this, NULL, settings, compositor_task_runner);
293 host_->SetRootLayer(root_web_layer_);
294 host_->SetLayerTreeHostClientReady();
297 Compositor::~Compositor() {
298 TRACE_EVENT0("shutdown", "Compositor::destructor");
300 DCHECK(g_compositor_initialized);
302 CancelCompositorLock();
303 DCHECK(!compositor_lock_);
305 if (root_layer_)
306 root_layer_->SetCompositor(NULL);
308 // Stop all outstanding draws before telling the ContextFactory to tear
309 // down any contexts that the |host_| may rely upon.
310 host_.reset();
312 ContextFactory::GetInstance()->RemoveCompositor(this);
315 // static
316 void Compositor::Initialize() {
317 #if defined(OS_CHROMEOS)
318 bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch(
319 switches::kUIDisableThreadedCompositing);
320 #else
321 bool use_thread =
322 CommandLine::ForCurrentProcess()->HasSwitch(
323 switches::kUIEnableThreadedCompositing) &&
324 !CommandLine::ForCurrentProcess()->HasSwitch(
325 switches::kUIDisableThreadedCompositing);
326 #endif
327 if (use_thread) {
328 g_compositor_thread = new base::Thread("Browser Compositor");
329 g_compositor_thread->Start();
332 DCHECK(!g_compositor_initialized) << "Compositor initialized twice.";
333 g_compositor_initialized = true;
336 // static
337 bool Compositor::WasInitializedWithThread() {
338 DCHECK(g_compositor_initialized);
339 return !!g_compositor_thread;
342 // static
343 scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() {
344 scoped_refptr<base::MessageLoopProxy> proxy;
345 if (g_compositor_thread)
346 proxy = g_compositor_thread->message_loop_proxy();
347 return proxy;
350 // static
351 void Compositor::Terminate() {
352 if (g_compositor_thread) {
353 g_compositor_thread->Stop();
354 delete g_compositor_thread;
355 g_compositor_thread = NULL;
358 DCHECK(g_compositor_initialized) << "Compositor::Initialize() didn't happen.";
359 g_compositor_initialized = false;
362 void Compositor::ScheduleDraw() {
363 if (g_compositor_thread) {
364 host_->Composite(gfx::FrameTime::Now());
365 } else if (!defer_draw_scheduling_) {
366 defer_draw_scheduling_ = true;
367 base::MessageLoop::current()->PostTask(
368 FROM_HERE,
369 base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr()));
373 void Compositor::SetRootLayer(Layer* root_layer) {
374 if (root_layer_ == root_layer)
375 return;
376 if (root_layer_)
377 root_layer_->SetCompositor(NULL);
378 root_layer_ = root_layer;
379 if (root_layer_ && !root_layer_->GetCompositor())
380 root_layer_->SetCompositor(this);
381 root_web_layer_->RemoveAllChildren();
382 if (root_layer_)
383 root_web_layer_->AddChild(root_layer_->cc_layer());
386 void Compositor::SetHostHasTransparentBackground(
387 bool host_has_transparent_background) {
388 host_->set_has_transparent_background(host_has_transparent_background);
391 void Compositor::Draw() {
392 DCHECK(!g_compositor_thread);
394 defer_draw_scheduling_ = false;
395 if (waiting_on_compositing_end_) {
396 draw_on_compositing_end_ = true;
397 return;
399 waiting_on_compositing_end_ = true;
401 TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_ + 1);
403 if (!root_layer_)
404 return;
406 last_started_frame_++;
407 PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get());
408 if (!IsLocked()) {
409 // TODO(nduca): Temporary while compositor calls
410 // compositeImmediately() directly.
411 Layout();
412 host_->Composite(gfx::FrameTime::Now());
414 #if defined(OS_WIN)
415 // While we resize, we are usually a few frames behind. By blocking
416 // the UI thread here we minize the area that is mis-painted, specially
417 // in the non-client area. See RenderWidgetHostViewAura::SetBounds for
418 // more details and bug 177115.
419 if (next_draw_is_resize_ && (last_ended_frame_ > 1)) {
420 next_draw_is_resize_ = false;
421 host_->FinishAllRendering();
423 #endif
426 if (!pending_swap.posted())
427 NotifyEnd();
430 void Compositor::ScheduleFullRedraw() {
431 host_->SetNeedsRedraw();
434 void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
435 host_->SetNeedsRedrawRect(damage_rect);
438 void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
439 host_->SetLatencyInfo(latency_info);
442 bool Compositor::ReadPixels(SkBitmap* bitmap,
443 const gfx::Rect& bounds_in_pixel) {
444 if (bounds_in_pixel.right() > size().width() ||
445 bounds_in_pixel.bottom() > size().height())
446 return false;
447 bitmap->setConfig(SkBitmap::kARGB_8888_Config,
448 bounds_in_pixel.width(), bounds_in_pixel.height());
449 bitmap->allocPixels();
450 SkAutoLockPixels lock_image(*bitmap);
451 unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels());
452 CancelCompositorLock();
453 PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get());
454 return host_->CompositeAndReadback(pixels, bounds_in_pixel);
457 void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
458 DCHECK_GT(scale, 0);
459 if (!size_in_pixel.IsEmpty()) {
460 size_ = size_in_pixel;
461 host_->SetViewportSize(size_in_pixel);
462 root_web_layer_->SetBounds(size_in_pixel);
464 next_draw_is_resize_ = true;
466 if (device_scale_factor_ != scale) {
467 device_scale_factor_ = scale;
468 if (root_layer_)
469 root_layer_->OnDeviceScaleFactorChanged(scale);
473 void Compositor::SetBackgroundColor(SkColor color) {
474 host_->set_background_color(color);
475 ScheduleDraw();
478 void Compositor::AddObserver(CompositorObserver* observer) {
479 observer_list_.AddObserver(observer);
482 void Compositor::RemoveObserver(CompositorObserver* observer) {
483 observer_list_.RemoveObserver(observer);
486 bool Compositor::HasObserver(CompositorObserver* observer) {
487 return observer_list_.HasObserver(observer);
490 void Compositor::OnSwapBuffersPosted() {
491 DCHECK(!g_compositor_thread);
492 posted_swaps_->PostSwap();
495 void Compositor::OnSwapBuffersComplete() {
496 DCHECK(!g_compositor_thread);
497 DCHECK(posted_swaps_->AreSwapsPosted());
498 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
499 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
500 NotifyEnd();
501 posted_swaps_->EndSwap();
504 void Compositor::OnSwapBuffersAborted() {
505 if (!g_compositor_thread) {
506 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
508 // We've just lost the context, so unwind all posted_swaps.
509 while (posted_swaps_->AreSwapsPosted()) {
510 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
511 NotifyEnd();
512 posted_swaps_->EndSwap();
516 FOR_EACH_OBSERVER(CompositorObserver,
517 observer_list_,
518 OnCompositingAborted(this));
521 void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase,
522 base::TimeDelta interval) {
523 FOR_EACH_OBSERVER(CompositorObserver,
524 observer_list_,
525 OnUpdateVSyncParameters(this, timebase, interval));
528 void Compositor::Layout() {
529 // We're sending damage that will be addressed during this composite
530 // cycle, so we don't need to schedule another composite to address it.
531 disable_schedule_composite_ = true;
532 if (root_layer_)
533 root_layer_->SendDamagedRects();
534 disable_schedule_composite_ = false;
537 scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) {
538 return ContextFactory::GetInstance()->CreateOutputSurface(this);
541 void Compositor::DidCommit() {
542 DCHECK(!IsLocked());
543 FOR_EACH_OBSERVER(CompositorObserver,
544 observer_list_,
545 OnCompositingDidCommit(this));
548 void Compositor::DidCommitAndDrawFrame() {
549 base::TimeTicks start_time = gfx::FrameTime::Now();
550 FOR_EACH_OBSERVER(CompositorObserver,
551 observer_list_,
552 OnCompositingStarted(this, start_time));
555 void Compositor::DidCompleteSwapBuffers() {
556 DCHECK(g_compositor_thread);
557 NotifyEnd();
560 void Compositor::ScheduleComposite() {
561 if (!disable_schedule_composite_)
562 ScheduleDraw();
565 scoped_refptr<cc::ContextProvider> Compositor::OffscreenContextProvider() {
566 return ContextFactory::GetInstance()->OffscreenCompositorContextProvider();
569 const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
570 return host_->debug_state();
573 void Compositor::SetLayerTreeDebugState(
574 const cc::LayerTreeDebugState& debug_state) {
575 host_->SetDebugState(debug_state);
578 scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
579 if (!compositor_lock_) {
580 compositor_lock_ = new CompositorLock(this);
581 if (g_compositor_thread)
582 host_->SetDeferCommits(true);
583 FOR_EACH_OBSERVER(CompositorObserver,
584 observer_list_,
585 OnCompositingLockStateChanged(this));
587 return compositor_lock_;
590 void Compositor::UnlockCompositor() {
591 DCHECK(compositor_lock_);
592 compositor_lock_ = NULL;
593 if (g_compositor_thread)
594 host_->SetDeferCommits(false);
595 FOR_EACH_OBSERVER(CompositorObserver,
596 observer_list_,
597 OnCompositingLockStateChanged(this));
600 void Compositor::CancelCompositorLock() {
601 if (compositor_lock_)
602 compositor_lock_->CancelLock();
605 void Compositor::NotifyEnd() {
606 last_ended_frame_++;
607 TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_);
608 waiting_on_compositing_end_ = false;
609 if (draw_on_compositing_end_) {
610 draw_on_compositing_end_ = false;
612 // Call ScheduleDraw() instead of Draw() in order to allow other
613 // CompositorObservers to be notified before starting another
614 // draw cycle.
615 ScheduleDraw();
617 FOR_EACH_OBSERVER(CompositorObserver,
618 observer_list_,
619 OnCompositingEnded(this));
622 } // namespace ui