> ash: Item removed animation visual polish.
[chromium-blink-merge.git] / ui / compositor / compositor.cc
blob9e7c4d54496ee96db23b3253c0519a9e2c6d90a8
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/message_loop.h"
13 #include "base/string_util.h"
14 #include "base/threading/thread.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "cc/font_atlas.h"
17 #include "cc/input_handler.h"
18 #include "cc/layer.h"
19 #include "cc/layer_tree_host.h"
20 #include "cc/output_surface.h"
21 #include "cc/thread_impl.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
23 #include "ui/compositor/compositor_observer.h"
24 #include "ui/compositor/compositor_switches.h"
25 #include "ui/compositor/dip_util.h"
26 #include "ui/compositor/layer.h"
27 #include "ui/compositor/test_web_graphics_context_3d.h"
28 #include "ui/gl/gl_context.h"
29 #include "ui/gl/gl_implementation.h"
30 #include "ui/gl/gl_surface.h"
31 #include "ui/gl/gl_switches.h"
32 #include "webkit/gpu/webgraphicscontext3d_in_process_impl.h"
34 #if defined(OS_CHROMEOS)
35 #include "base/chromeos/chromeos_version.h"
36 #endif
38 namespace {
40 const double kDefaultRefreshRate = 60.0;
41 const double kTestRefreshRate = 100.0;
43 enum SwapType {
44 DRAW_SWAP,
45 READPIXELS_SWAP,
48 base::Thread* g_compositor_thread = NULL;
50 bool g_test_compositor_enabled = false;
52 ui::ContextFactory* g_context_factory = NULL;
54 const int kCompositorLockTimeoutMs = 67;
56 // Adapts a pure WebGraphicsContext3D into a cc::OutputSurface.
57 class WebGraphicsContextToOutputSurfaceAdapter
58 : public cc::OutputSurface {
59 public:
60 explicit WebGraphicsContextToOutputSurfaceAdapter(
61 WebKit::WebGraphicsContext3D* context)
62 : context3D_(context),
63 client_(NULL) {
66 virtual bool BindToClient(
67 cc::OutputSurfaceClient* client) OVERRIDE {
68 DCHECK(client);
69 if (!context3D_->makeContextCurrent())
70 return false;
71 client_ = client;
72 return true;
75 virtual const struct Capabilities& Capabilities() const OVERRIDE {
76 return capabilities_;
79 virtual WebKit::WebGraphicsContext3D* Context3D() const OVERRIDE {
80 return context3D_.get();
83 virtual cc::SoftwareOutputDevice* SoftwareDevice() const OVERRIDE {
84 return NULL;
87 virtual void SendFrameToParentCompositor(cc::CompositorFrame*) OVERRIDE {
90 private:
91 scoped_ptr<WebKit::WebGraphicsContext3D> context3D_;
92 struct Capabilities capabilities_;
93 cc::OutputSurfaceClient* client_;
96 class PendingSwap {
97 public:
98 PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps);
99 ~PendingSwap();
101 SwapType type() const { return type_; }
102 bool posted() const { return posted_; }
104 private:
105 friend class ui::PostedSwapQueue;
107 SwapType type_;
108 bool posted_;
109 ui::PostedSwapQueue* posted_swaps_;
111 DISALLOW_COPY_AND_ASSIGN(PendingSwap);
114 } // namespace
116 namespace ui {
118 // static
119 ContextFactory* ContextFactory::GetInstance() {
120 // We leak the shared resources so that we don't race with
121 // the tear down of the gl_bindings.
122 if (!g_context_factory) {
123 DVLOG(1) << "Using DefaultSharedResource";
124 scoped_ptr<DefaultContextFactory> instance(
125 new DefaultContextFactory());
126 if (instance->Initialize())
127 g_context_factory = instance.release();
129 return g_context_factory;
132 // static
133 void ContextFactory::SetInstance(ContextFactory* instance) {
134 g_context_factory = instance;
137 DefaultContextFactory::DefaultContextFactory() {
140 DefaultContextFactory::~DefaultContextFactory() {
143 bool DefaultContextFactory::Initialize() {
144 // The following line of code exists soley to disable IO restrictions
145 // on this thread long enough to perform the GL bindings.
146 // TODO(wjmaclean) Remove this when GL initialisation cleaned up.
147 base::ThreadRestrictions::ScopedAllowIO allow_io;
148 if (!gfx::GLSurface::InitializeOneOff() ||
149 gfx::GetGLImplementation() == gfx::kGLImplementationNone) {
150 LOG(ERROR) << "Could not load the GL bindings";
151 return false;
153 return true;
156 cc::OutputSurface* DefaultContextFactory::CreateOutputSurface(
157 Compositor* compositor) {
158 return new WebGraphicsContextToOutputSurfaceAdapter(
159 CreateContextCommon(compositor, false));
162 WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateOffscreenContext() {
163 return CreateContextCommon(NULL, true);
166 void DefaultContextFactory::RemoveCompositor(Compositor* compositor) {
169 WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContextCommon(
170 Compositor* compositor,
171 bool offscreen) {
172 DCHECK(offscreen || compositor);
173 WebKit::WebGraphicsContext3D::Attributes attrs;
174 attrs.depth = false;
175 attrs.stencil = false;
176 attrs.antialias = false;
177 attrs.shareResources = true;
178 WebKit::WebGraphicsContext3D* context =
179 offscreen ?
180 webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWebView(
181 attrs, false) :
182 webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWindow(
183 attrs, compositor->widget(), share_group_.get());
184 if (!context)
185 return NULL;
187 CommandLine* command_line = CommandLine::ForCurrentProcess();
188 if (!offscreen) {
189 context->makeContextCurrent();
190 gfx::GLContext* gl_context = gfx::GLContext::GetCurrent();
191 bool vsync = !command_line->HasSwitch(switches::kDisableGpuVsync);
192 gl_context->SetSwapInterval(vsync ? 1 : 0);
193 gl_context->ReleaseCurrent(NULL);
195 return context;
198 Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor)
199 : size_(size),
200 flipped_(flipped),
201 device_scale_factor_(device_scale_factor) {
204 Texture::~Texture() {
207 std::string Texture::Produce() {
208 return EmptyString();
211 CompositorLock::CompositorLock(Compositor* compositor)
212 : compositor_(compositor) {
213 MessageLoop::current()->PostDelayedTask(
214 FROM_HERE,
215 base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
216 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
219 CompositorLock::~CompositorLock() {
220 CancelLock();
223 void CompositorLock::CancelLock() {
224 if (!compositor_)
225 return;
226 compositor_->UnlockCompositor();
227 compositor_ = NULL;
230 class PostedSwapQueue {
231 public:
232 PostedSwapQueue() : pending_swap_(NULL) {
235 ~PostedSwapQueue() {
236 DCHECK(!pending_swap_);
239 SwapType NextPostedSwap() const {
240 return queue_.front();
243 bool AreSwapsPosted() const {
244 return !queue_.empty();
247 int NumSwapsPosted(SwapType type) const {
248 int count = 0;
249 for (std::deque<SwapType>::const_iterator it = queue_.begin();
250 it != queue_.end(); ++it) {
251 if (*it == type)
252 count++;
254 return count;
257 void PostSwap() {
258 DCHECK(pending_swap_);
259 queue_.push_back(pending_swap_->type());
260 pending_swap_->posted_ = true;
263 void EndSwap() {
264 queue_.pop_front();
267 private:
268 friend class ::PendingSwap;
270 PendingSwap* pending_swap_;
271 std::deque<SwapType> queue_;
273 DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue);
276 } // namespace ui
278 namespace {
280 PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps)
281 : type_(type), posted_(false), posted_swaps_(posted_swaps) {
282 // Only one pending swap in flight.
283 DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_);
284 posted_swaps_->pending_swap_ = this;
287 PendingSwap::~PendingSwap() {
288 DCHECK_EQ(this, posted_swaps_->pending_swap_);
289 posted_swaps_->pending_swap_ = NULL;
292 } // namespace
294 namespace ui {
296 Compositor::Compositor(CompositorDelegate* delegate,
297 gfx::AcceleratedWidget widget)
298 : delegate_(delegate),
299 root_layer_(NULL),
300 widget_(widget),
301 posted_swaps_(new PostedSwapQueue()),
302 device_scale_factor_(0.0f),
303 last_started_frame_(0),
304 last_ended_frame_(0),
305 disable_schedule_composite_(false),
306 compositor_lock_(NULL) {
307 root_web_layer_ = cc::Layer::create();
308 root_web_layer_->setAnchorPoint(gfx::PointF(0.f, 0.f));
310 CommandLine* command_line = CommandLine::ForCurrentProcess();
311 cc::LayerTreeSettings settings;
312 settings.initialDebugState.showFPSCounter =
313 command_line->HasSwitch(switches::kUIShowFPSCounter);
314 settings.initialDebugState.showPlatformLayerTree =
315 command_line->HasSwitch(switches::kUIShowLayerTree);
316 settings.refreshRate =
317 g_test_compositor_enabled ? kTestRefreshRate : kDefaultRefreshRate;
318 settings.initialDebugState.showDebugBorders =
319 command_line->HasSwitch(switches::kUIShowLayerBorders);
320 settings.partialSwapEnabled =
321 command_line->HasSwitch(switches::kUIEnablePartialSwap);
322 settings.perTilePaintingEnabled =
323 command_line->HasSwitch(switches::kUIEnablePerTilePainting);
325 scoped_ptr<cc::Thread> thread;
326 if (g_compositor_thread) {
327 thread = cc::ThreadImpl::createForDifferentThread(
328 g_compositor_thread->message_loop_proxy());
331 host_ = cc::LayerTreeHost::create(this, settings, thread.Pass());
332 host_->setRootLayer(root_web_layer_);
333 host_->setSurfaceReady();
336 Compositor::~Compositor() {
337 CancelCompositorLock();
338 DCHECK(!compositor_lock_);
340 // Don't call |CompositorDelegate::ScheduleDraw| from this point.
341 delegate_ = NULL;
342 if (root_layer_)
343 root_layer_->SetCompositor(NULL);
345 // Stop all outstanding draws before telling the ContextFactory to tear
346 // down any contexts that the |host_| may rely upon.
347 host_.reset();
349 if (!g_test_compositor_enabled)
350 ContextFactory::GetInstance()->RemoveCompositor(this);
353 void Compositor::Initialize(bool use_thread) {
354 if (use_thread) {
355 g_compositor_thread = new base::Thread("Browser Compositor");
356 g_compositor_thread->Start();
360 void Compositor::Terminate() {
361 if (g_compositor_thread) {
362 g_compositor_thread->Stop();
363 delete g_compositor_thread;
364 g_compositor_thread = NULL;
368 void Compositor::ScheduleDraw() {
369 if (g_compositor_thread)
370 host_->composite();
371 else if (delegate_)
372 delegate_->ScheduleDraw();
375 void Compositor::SetRootLayer(Layer* root_layer) {
376 if (root_layer_ == root_layer)
377 return;
378 if (root_layer_)
379 root_layer_->SetCompositor(NULL);
380 root_layer_ = root_layer;
381 if (root_layer_ && !root_layer_->GetCompositor())
382 root_layer_->SetCompositor(this);
383 root_web_layer_->removeAllChildren();
384 if (root_layer_)
385 root_web_layer_->addChild(root_layer_->cc_layer());
388 void Compositor::SetHostHasTransparentBackground(
389 bool host_has_transparent_background) {
390 host_->setHasTransparentBackground(host_has_transparent_background);
393 void Compositor::Draw(bool force_clear) {
394 DCHECK(!g_compositor_thread);
396 if (!root_layer_)
397 return;
399 last_started_frame_++;
400 PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get());
401 if (!IsLocked()) {
402 // TODO(nduca): Temporary while compositor calls
403 // compositeImmediately() directly.
404 layout();
405 host_->composite();
407 if (!pending_swap.posted())
408 NotifyEnd();
411 void Compositor::ScheduleFullDraw() {
412 host_->setNeedsRedraw();
415 bool Compositor::ReadPixels(SkBitmap* bitmap,
416 const gfx::Rect& bounds_in_pixel) {
417 if (bounds_in_pixel.right() > size().width() ||
418 bounds_in_pixel.bottom() > size().height())
419 return false;
420 bitmap->setConfig(SkBitmap::kARGB_8888_Config,
421 bounds_in_pixel.width(), bounds_in_pixel.height());
422 bitmap->allocPixels();
423 SkAutoLockPixels lock_image(*bitmap);
424 unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels());
425 CancelCompositorLock();
426 PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get());
427 return host_->compositeAndReadback(pixels, bounds_in_pixel);
430 void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
431 DCHECK_GT(scale, 0);
432 if (!size_in_pixel.IsEmpty()) {
433 size_ = size_in_pixel;
434 host_->setViewportSize(size_in_pixel, size_in_pixel);
435 root_web_layer_->setBounds(size_in_pixel);
437 if (device_scale_factor_ != scale) {
438 device_scale_factor_ = scale;
439 if (root_layer_)
440 root_layer_->OnDeviceScaleFactorChanged(scale);
444 void Compositor::AddObserver(CompositorObserver* observer) {
445 observer_list_.AddObserver(observer);
448 void Compositor::RemoveObserver(CompositorObserver* observer) {
449 observer_list_.RemoveObserver(observer);
452 bool Compositor::HasObserver(CompositorObserver* observer) {
453 return observer_list_.HasObserver(observer);
456 void Compositor::OnSwapBuffersPosted() {
457 DCHECK(!g_compositor_thread);
458 posted_swaps_->PostSwap();
461 void Compositor::OnSwapBuffersComplete() {
462 DCHECK(!g_compositor_thread);
463 DCHECK(posted_swaps_->AreSwapsPosted());
464 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
465 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
466 NotifyEnd();
467 posted_swaps_->EndSwap();
470 void Compositor::OnSwapBuffersAborted() {
471 DCHECK(!g_compositor_thread);
472 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
474 // We've just lost the context, so unwind all posted_swaps.
475 while (posted_swaps_->AreSwapsPosted()) {
476 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
477 NotifyEnd();
478 posted_swaps_->EndSwap();
481 FOR_EACH_OBSERVER(CompositorObserver,
482 observer_list_,
483 OnCompositingAborted(this));
486 void Compositor::willBeginFrame() {
489 void Compositor::didBeginFrame() {
492 void Compositor::animate(double frameBeginTime) {
495 void Compositor::layout() {
496 // We're sending damage that will be addressed during this composite
497 // cycle, so we don't need to schedule another composite to address it.
498 disable_schedule_composite_ = true;
499 if (root_layer_)
500 root_layer_->SendDamagedRects();
501 disable_schedule_composite_ = false;
504 void Compositor::applyScrollAndScale(gfx::Vector2d scrollDelta,
505 float pageScale) {
508 scoped_ptr<cc::OutputSurface> Compositor::createOutputSurface() {
509 if (g_test_compositor_enabled) {
510 ui::TestWebGraphicsContext3D* test_context =
511 new ui::TestWebGraphicsContext3D();
512 test_context->Initialize();
513 return scoped_ptr<cc::OutputSurface>(
514 new WebGraphicsContextToOutputSurfaceAdapter(test_context));
515 } else {
516 return scoped_ptr<cc::OutputSurface>(
517 ContextFactory::GetInstance()->CreateOutputSurface(this));
521 void Compositor::didRecreateOutputSurface(bool success) {
524 scoped_ptr<cc::InputHandler> Compositor::createInputHandler() {
525 return scoped_ptr<cc::InputHandler>();
528 void Compositor::willCommit() {
531 void Compositor::didCommit() {
532 DCHECK(!IsLocked());
533 FOR_EACH_OBSERVER(CompositorObserver,
534 observer_list_,
535 OnCompositingDidCommit(this));
538 void Compositor::didCommitAndDrawFrame() {
539 FOR_EACH_OBSERVER(CompositorObserver,
540 observer_list_,
541 OnCompositingStarted(this));
544 void Compositor::didCompleteSwapBuffers() {
545 DCHECK(g_compositor_thread);
546 NotifyEnd();
549 void Compositor::scheduleComposite() {
550 if (!disable_schedule_composite_)
551 ScheduleDraw();
554 scoped_ptr<cc::FontAtlas> Compositor::createFontAtlas() {
555 return scoped_ptr<cc::FontAtlas>();
558 scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
559 if (!compositor_lock_) {
560 compositor_lock_ = new CompositorLock(this);
561 if (g_compositor_thread)
562 host_->setDeferCommits(true);
563 FOR_EACH_OBSERVER(CompositorObserver,
564 observer_list_,
565 OnCompositingLockStateChanged(this));
567 return compositor_lock_;
570 void Compositor::UnlockCompositor() {
571 DCHECK(compositor_lock_);
572 compositor_lock_ = NULL;
573 if (g_compositor_thread)
574 host_->setDeferCommits(false);
575 FOR_EACH_OBSERVER(CompositorObserver,
576 observer_list_,
577 OnCompositingLockStateChanged(this));
580 void Compositor::CancelCompositorLock() {
581 if (compositor_lock_)
582 compositor_lock_->CancelLock();
585 void Compositor::NotifyEnd() {
586 last_ended_frame_++;
587 FOR_EACH_OBSERVER(CompositorObserver,
588 observer_list_,
589 OnCompositingEnded(this));
592 COMPOSITOR_EXPORT void SetupTestCompositor() {
593 if (!CommandLine::ForCurrentProcess()->HasSwitch(
594 switches::kDisableTestCompositor)) {
595 g_test_compositor_enabled = true;
597 #if defined(OS_CHROMEOS)
598 // If the test is running on the chromeos envrionment (such as
599 // device or vm bots), use the real compositor.
600 if (base::chromeos::IsRunningOnChromeOS())
601 g_test_compositor_enabled = false;
602 #endif
605 COMPOSITOR_EXPORT void DisableTestCompositor() {
606 g_test_compositor_enabled = false;
609 COMPOSITOR_EXPORT bool IsTestCompositorEnabled() {
610 return g_test_compositor_enabled;
613 } // namespace ui