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"
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"
36 const double kDefaultRefreshRate
= 60.0;
37 const double kTestRefreshRate
= 200.0;
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;
53 PendingSwap(SwapType type
, ui::PostedSwapQueue
* posted_swaps
);
56 SwapType
type() const { return type_
; }
57 bool posted() const { return posted_
; }
60 friend class ui::PostedSwapQueue
;
64 ui::PostedSwapQueue
* posted_swaps_
;
66 DISALLOW_COPY_AND_ASSIGN(PendingSwap
);
74 ContextFactory
* ContextFactory::GetInstance() {
75 DCHECK(g_context_factory
);
76 return g_context_factory
;
80 void ContextFactory::SetInstance(ContextFactory
* instance
) {
81 g_context_factory
= instance
;
84 Texture::Texture(bool flipped
, const gfx::Size
& size
, float device_scale_factor
)
87 device_scale_factor_(device_scale_factor
) {
93 std::string
Texture::Produce() {
97 CompositorLock::CompositorLock(Compositor
* compositor
)
98 : compositor_(compositor
) {
99 base::MessageLoop::current()->PostDelayedTask(
101 base::Bind(&CompositorLock::CancelLock
, AsWeakPtr()),
102 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs
));
105 CompositorLock::~CompositorLock() {
109 void CompositorLock::CancelLock() {
112 compositor_
->UnlockCompositor();
117 void DrawWaiterForTest::Wait(Compositor
* compositor
) {
118 DrawWaiterForTest waiter
;
119 waiter
.wait_for_commit_
= false;
120 waiter
.WaitImpl(compositor
);
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
{
170 PostedSwapQueue() : pending_swap_(NULL
) {
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 {
187 for (std::deque
<SwapType
>::const_iterator it
= queue_
.begin();
188 it
!= queue_
.end(); ++it
) {
196 DCHECK(pending_swap_
);
197 queue_
.push_back(pending_swap_
->type());
198 pending_swap_
->posted_
= true;
206 friend class ::PendingSwap
;
208 PendingSwap
* pending_swap_
;
209 std::deque
<SwapType
> queue_
;
211 DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue
);
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
;
234 Compositor::Compositor(gfx::AcceleratedWidget 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()
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
;
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_
);
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.
312 ContextFactory::GetInstance()->RemoveCompositor(this);
316 void Compositor::Initialize() {
317 #if defined(OS_CHROMEOS)
318 bool use_thread
= !CommandLine::ForCurrentProcess()->HasSwitch(
319 switches::kUIDisableThreadedCompositing
);
322 CommandLine::ForCurrentProcess()->HasSwitch(
323 switches::kUIEnableThreadedCompositing
) &&
324 !CommandLine::ForCurrentProcess()->HasSwitch(
325 switches::kUIDisableThreadedCompositing
);
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;
337 bool Compositor::WasInitializedWithThread() {
338 DCHECK(g_compositor_initialized
);
339 return !!g_compositor_thread
;
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();
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(
369 base::Bind(&Compositor::Draw
, schedule_draw_factory_
.GetWeakPtr()));
373 void Compositor::SetRootLayer(Layer
* root_layer
) {
374 if (root_layer_
== 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();
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;
399 waiting_on_compositing_end_
= true;
401 TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_
+ 1);
406 last_started_frame_
++;
407 PendingSwap
pending_swap(DRAW_SWAP
, posted_swaps_
.get());
409 // TODO(nduca): Temporary while compositor calls
410 // compositeImmediately() directly.
412 host_
->Composite(gfx::FrameTime::Now());
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();
426 if (!pending_swap
.posted())
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())
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
) {
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
;
469 root_layer_
->OnDeviceScaleFactorChanged(scale
);
473 void Compositor::SetBackgroundColor(SkColor color
) {
474 host_
->set_background_color(color
);
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
)
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
)
512 posted_swaps_
->EndSwap();
516 FOR_EACH_OBSERVER(CompositorObserver
,
518 OnCompositingAborted(this));
521 void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase
,
522 base::TimeDelta interval
) {
523 FOR_EACH_OBSERVER(CompositorObserver
,
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;
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() {
543 FOR_EACH_OBSERVER(CompositorObserver
,
545 OnCompositingDidCommit(this));
548 void Compositor::DidCommitAndDrawFrame() {
549 base::TimeTicks start_time
= gfx::FrameTime::Now();
550 FOR_EACH_OBSERVER(CompositorObserver
,
552 OnCompositingStarted(this, start_time
));
555 void Compositor::DidCompleteSwapBuffers() {
556 DCHECK(g_compositor_thread
);
560 void Compositor::ScheduleComposite() {
561 if (!disable_schedule_composite_
)
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
,
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
,
597 OnCompositingLockStateChanged(this));
600 void Compositor::CancelCompositorLock() {
601 if (compositor_lock_
)
602 compositor_lock_
->CancelLock();
605 void Compositor::NotifyEnd() {
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
617 FOR_EACH_OBSERVER(CompositorObserver
,
619 OnCompositingEnded(this));