Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / android / in_process / synchronous_compositor_impl.cc
blob98466724ed1cdd690fcb7f4672bf3f30fed87e30
1 // Copyright 2013 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 "content/browser/android/in_process/synchronous_compositor_impl.h"
7 #include "base/auto_reset.h"
8 #include "base/bind.h"
9 #include "base/lazy_instance.h"
10 #include "base/message_loop/message_loop.h"
11 #include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
12 #include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
13 #include "content/browser/android/in_process/synchronous_compositor_registry.h"
14 #include "content/browser/android/in_process/synchronous_input_event_filter.h"
15 #include "content/browser/gpu/gpu_process_host.h"
16 #include "content/browser/renderer_host/render_widget_host_view_android.h"
17 #include "content/common/input/did_overscroll_params.h"
18 #include "content/common/input_messages.h"
19 #include "content/public/browser/android/synchronous_compositor_client.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "ui/gfx/geometry/scroll_offset.h"
24 #include "ui/gl/gl_surface.h"
26 namespace content {
28 namespace {
30 int GetInProcessRendererId() {
31 content::RenderProcessHost::iterator it =
32 content::RenderProcessHost::AllHostsIterator();
33 if (it.IsAtEnd()) {
34 // There should always be one RPH in single process mode.
35 NOTREACHED();
36 return 0;
39 int id = it.GetCurrentValue()->GetID();
40 it.Advance();
41 DCHECK(it.IsAtEnd()); // Not multiprocess compatible.
42 return id;
45 base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
46 LAZY_INSTANCE_INITIALIZER;
48 base::Thread* CreateInProcessGpuThreadForSynchronousCompositor(
49 const InProcessChildThreadParams& params) {
50 return g_factory.Get().CreateInProcessGpuThread(params);
53 } // namespace
55 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl);
57 // static
58 SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
59 int routing_id) {
60 if (g_factory == nullptr)
61 return nullptr;
62 RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
63 if (!rvh)
64 return nullptr;
65 WebContents* contents = WebContents::FromRenderViewHost(rvh);
66 if (!contents)
67 return nullptr;
68 return FromWebContents(contents);
71 SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
72 int routing_id) {
73 return FromID(GetInProcessRendererId(), routing_id);
76 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents)
77 : compositor_client_(nullptr),
78 output_surface_(nullptr),
79 begin_frame_source_(nullptr),
80 contents_(contents),
81 routing_id_(contents->GetRoutingID()),
82 synchronous_input_handler_proxy_(nullptr),
83 registered_with_client_(false),
84 is_active_(true),
85 renderer_needs_begin_frames_(false),
86 need_animate_input_(false),
87 weak_ptr_factory_(this) {
88 DCHECK(contents);
89 DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
92 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
93 DCHECK(!output_surface_);
94 DCHECK(!begin_frame_source_);
95 DCHECK(!synchronous_input_handler_proxy_);
98 void SynchronousCompositorImpl::SetClient(
99 SynchronousCompositorClient* compositor_client) {
100 DCHECK(CalledOnValidThread());
101 DCHECK_IMPLIES(compositor_client, !compositor_client_);
102 DCHECK_IMPLIES(!compositor_client, compositor_client_);
104 if (!compositor_client) {
105 SynchronousCompositorRegistry::GetInstance()->UnregisterCompositor(
106 routing_id_, this);
109 compositor_client_ = compositor_client;
111 // SetClient is essentially the constructor and destructor of
112 // SynchronousCompositorImpl.
113 if (compositor_client_) {
114 SynchronousCompositorRegistry::GetInstance()->RegisterCompositor(
115 routing_id_, this);
119 void SynchronousCompositorImpl::RegisterWithClient() {
120 DCHECK(CalledOnValidThread());
121 DCHECK(compositor_client_);
122 DCHECK(output_surface_);
123 DCHECK(synchronous_input_handler_proxy_);
124 DCHECK(!registered_with_client_);
125 registered_with_client_ = true;
127 compositor_client_->DidInitializeCompositor(this);
129 output_surface_->SetTreeActivationCallback(
130 base::Bind(&SynchronousCompositorImpl::DidActivatePendingTree,
131 weak_ptr_factory_.GetWeakPtr()));
133 // This disables the input system from animating inputs autonomously, instead
134 // routing all input animations through the SynchronousInputHandler, which is
135 // |this| class. Calling this causes an UpdateRootLayerState() immediately so,
136 // do it after setting the client.
137 synchronous_input_handler_proxy_->SetOnlySynchronouslyAnimateRootFlings(this);
140 // static
141 void SynchronousCompositor::SetGpuService(
142 scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
143 g_factory.Get().SetDeferredGpuService(service);
144 GpuProcessHost::RegisterGpuMainThreadFactory(
145 CreateInProcessGpuThreadForSynchronousCompositor);
148 // static
149 void SynchronousCompositor::SetUseIpcCommandBuffer() {
150 g_factory.Get().SetUseIpcCommandBuffer();
153 void SynchronousCompositorImpl::DidInitializeRendererObjects(
154 SynchronousCompositorOutputSurface* output_surface,
155 SynchronousCompositorExternalBeginFrameSource* begin_frame_source,
156 SynchronousInputHandlerProxy* synchronous_input_handler_proxy) {
157 DCHECK(!output_surface_);
158 DCHECK(!begin_frame_source_);
159 DCHECK(output_surface);
160 DCHECK(begin_frame_source);
161 DCHECK(compositor_client_);
162 DCHECK(synchronous_input_handler_proxy);
164 output_surface_ = output_surface;
165 begin_frame_source_ = begin_frame_source;
166 synchronous_input_handler_proxy_ = synchronous_input_handler_proxy;
168 output_surface_->SetCompositor(this);
169 begin_frame_source_->SetCompositor(this);
172 void SynchronousCompositorImpl::DidDestroyRendererObjects() {
173 DCHECK(output_surface_);
174 DCHECK(begin_frame_source_);
175 DCHECK(compositor_client_);
177 if (registered_with_client_) {
178 output_surface_->SetTreeActivationCallback(base::Closure());
179 compositor_client_->DidDestroyCompositor(this);
180 registered_with_client_ = false;
183 // This object is being destroyed, so remove pointers to it.
184 begin_frame_source_->SetCompositor(nullptr);
185 output_surface_->SetCompositor(nullptr);
186 synchronous_input_handler_proxy_->SetOnlySynchronouslyAnimateRootFlings(
187 nullptr);
189 synchronous_input_handler_proxy_ = nullptr;
190 begin_frame_source_ = nullptr;
191 output_surface_ = nullptr;
192 // Don't propogate this signal from one renderer to the next.
193 need_animate_input_ = false;
196 scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
197 gfx::Size surface_size,
198 const gfx::Transform& transform,
199 gfx::Rect viewport,
200 gfx::Rect clip,
201 gfx::Rect viewport_rect_for_tile_priority,
202 const gfx::Transform& transform_for_tile_priority) {
203 DCHECK(CalledOnValidThread());
204 DCHECK(output_surface_);
205 DCHECK(compositor_client_);
206 DCHECK(begin_frame_source_);
208 scoped_ptr<cc::CompositorFrame> frame =
209 output_surface_->DemandDrawHw(surface_size,
210 transform,
211 viewport,
212 clip,
213 viewport_rect_for_tile_priority,
214 transform_for_tile_priority);
216 if (frame.get())
217 UpdateFrameMetaData(frame->metadata);
219 return frame.Pass();
222 void SynchronousCompositorImpl::ReturnResources(
223 const cc::CompositorFrameAck& frame_ack) {
224 DCHECK(CalledOnValidThread());
225 output_surface_->ReturnResources(frame_ack);
228 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
229 DCHECK(CalledOnValidThread());
230 DCHECK(output_surface_);
231 DCHECK(compositor_client_);
232 DCHECK(begin_frame_source_);
234 scoped_ptr<cc::CompositorFrame> frame =
235 output_surface_->DemandDrawSw(canvas);
237 if (frame.get())
238 UpdateFrameMetaData(frame->metadata);
240 return !!frame.get();
243 void SynchronousCompositorImpl::UpdateFrameMetaData(
244 const cc::CompositorFrameMetadata& frame_metadata) {
245 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
246 contents_->GetRenderWidgetHostView());
247 if (rwhv)
248 rwhv->SynchronousFrameMetadata(frame_metadata);
249 DeliverMessages();
252 void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit) {
253 DCHECK(CalledOnValidThread());
254 DCHECK(output_surface_);
256 size_t current_bytes_limit = output_surface_->GetMemoryPolicy();
257 output_surface_->SetMemoryPolicy(bytes_limit);
259 if (bytes_limit && !current_bytes_limit) {
260 g_factory.Get().CompositorInitializedHardwareDraw();
261 } else if (!bytes_limit && current_bytes_limit) {
262 g_factory.Get().CompositorReleasedHardwareDraw();
266 void SynchronousCompositorImpl::PostInvalidate() {
267 DCHECK(CalledOnValidThread());
268 DCHECK(compositor_client_);
269 if (registered_with_client_)
270 compositor_client_->PostInvalidate();
273 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset(
274 const gfx::ScrollOffset& root_offset) {
275 DCHECK(CalledOnValidThread());
276 if (!synchronous_input_handler_proxy_)
277 return;
278 synchronous_input_handler_proxy_->SynchronouslySetRootScrollOffset(
279 root_offset);
282 void SynchronousCompositorImpl::SetIsActive(bool is_active) {
283 TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active",
284 is_active);
285 is_active_ = is_active;
286 UpdateNeedsBeginFrames();
289 void SynchronousCompositorImpl::OnComputeScroll(
290 base::TimeTicks animation_time) {
291 if (need_animate_input_) {
292 need_animate_input_ = false;
293 synchronous_input_handler_proxy_->SynchronouslyAnimate(animation_time);
297 void SynchronousCompositorImpl::OnNeedsBeginFramesChange(
298 bool needs_begin_frames) {
299 renderer_needs_begin_frames_ = needs_begin_frames;
300 UpdateNeedsBeginFrames();
303 void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs& args) {
304 if (!registered_with_client_ && is_active_ && renderer_needs_begin_frames_) {
305 // Make sure this is a BeginFrame that renderer side explicitly requested.
306 // Otherwise it is possible renderer objects not initialized.
307 RegisterWithClient();
308 DCHECK(registered_with_client_);
310 if (begin_frame_source_)
311 begin_frame_source_->BeginFrame(args);
314 void SynchronousCompositorImpl::UpdateNeedsBeginFrames() {
315 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
316 contents_->GetRenderWidgetHostView());
317 if (rwhv)
318 rwhv->OnSetNeedsBeginFrames(is_active_ && renderer_needs_begin_frames_);
321 void SynchronousCompositorImpl::DidOverscroll(
322 const DidOverscrollParams& params) {
323 DCHECK(compositor_client_);
324 if (registered_with_client_) {
325 compositor_client_->DidOverscroll(params.accumulated_overscroll,
326 params.latest_overscroll_delta,
327 params.current_fling_velocity);
331 void SynchronousCompositorImpl::DidStopFlinging() {
332 // It's important that the fling-end notification follow the same path as it
333 // takes on other platforms (using an IPC). This ensures consistent
334 // bookkeeping at all stages of the input pipeline.
335 contents_->GetRenderProcessHost()->OnMessageReceived(
336 InputHostMsg_DidStopFlinging(routing_id_));
339 InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
340 const blink::WebInputEvent& input_event) {
341 DCHECK(CalledOnValidThread());
342 return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent(
343 contents_->GetRoutingID(), input_event);
346 void SynchronousCompositorImpl::DeliverMessages() {
347 ScopedVector<IPC::Message> messages;
348 output_surface_->GetMessagesToDeliver(&messages);
349 RenderProcessHost* rph = contents_->GetRenderProcessHost();
350 for (ScopedVector<IPC::Message>::const_iterator i = messages.begin();
351 i != messages.end();
352 ++i) {
353 rph->OnMessageReceived(**i);
357 void SynchronousCompositorImpl::DidActivatePendingTree() {
358 DCHECK(compositor_client_);
359 if (registered_with_client_)
360 compositor_client_->DidUpdateContent();
361 DeliverMessages();
364 void SynchronousCompositorImpl::SetNeedsSynchronousAnimateInput() {
365 DCHECK(CalledOnValidThread());
366 DCHECK(compositor_client_);
367 if (!registered_with_client_)
368 return;
369 need_animate_input_ = true;
370 compositor_client_->PostInvalidate();
373 void SynchronousCompositorImpl::UpdateRootLayerState(
374 const gfx::ScrollOffset& total_scroll_offset,
375 const gfx::ScrollOffset& max_scroll_offset,
376 const gfx::SizeF& scrollable_size,
377 float page_scale_factor,
378 float min_page_scale_factor,
379 float max_page_scale_factor) {
380 DCHECK(CalledOnValidThread());
381 DCHECK(compositor_client_);
383 if (registered_with_client_) {
384 // TODO(miletus): Pass in ScrollOffset. crbug.com/414283.
385 compositor_client_->UpdateRootLayerState(
386 gfx::ScrollOffsetToVector2dF(total_scroll_offset),
387 gfx::ScrollOffsetToVector2dF(max_scroll_offset),
388 scrollable_size,
389 page_scale_factor,
390 min_page_scale_factor,
391 max_page_scale_factor);
395 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
396 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
397 bool SynchronousCompositorImpl::CalledOnValidThread() const {
398 return BrowserThread::CurrentlyOn(BrowserThread::UI);
401 // static
402 void SynchronousCompositor::SetClientForWebContents(
403 WebContents* contents,
404 SynchronousCompositorClient* client) {
405 DCHECK(contents);
406 if (client) {
407 g_factory.Get(); // Ensure it's initialized.
408 SynchronousCompositorImpl::CreateForWebContents(contents);
410 SynchronousCompositorImpl* instance =
411 SynchronousCompositorImpl::FromWebContents(contents);
412 DCHECK(instance);
413 instance->SetClient(client);
416 } // namespace content