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"
9 #include "base/lazy_instance.h"
10 #include "base/message_loop/message_loop.h"
11 #include "cc/input/input_handler.h"
12 #include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
13 #include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
14 #include "content/browser/android/in_process/synchronous_compositor_registry.h"
15 #include "content/browser/android/in_process/synchronous_input_event_filter.h"
16 #include "content/browser/gpu/gpu_process_host.h"
17 #include "content/browser/renderer_host/render_widget_host_view_android.h"
18 #include "content/common/input/did_overscroll_params.h"
19 #include "content/common/input_messages.h"
20 #include "content/public/browser/android/synchronous_compositor_client.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "ui/gl/gl_surface.h"
30 int GetInProcessRendererId() {
31 content::RenderProcessHost::iterator it
=
32 content::RenderProcessHost::AllHostsIterator();
34 // There should always be one RPH in single process mode.
39 int id
= it
.GetCurrentValue()->GetID();
41 DCHECK(it
.IsAtEnd()); // Not multiprocess compatible.
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
);
55 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl
);
58 SynchronousCompositorImpl
* SynchronousCompositorImpl::FromID(int process_id
,
60 if (g_factory
== nullptr)
62 RenderViewHost
* rvh
= RenderViewHost::FromID(process_id
, routing_id
);
65 WebContents
* contents
= WebContents::FromRenderViewHost(rvh
);
68 return FromWebContents(contents
);
71 SynchronousCompositorImpl
* SynchronousCompositorImpl::FromRoutingID(
73 return FromID(GetInProcessRendererId(), routing_id
);
76 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents
* contents
)
77 : compositor_client_(nullptr),
78 output_surface_(nullptr),
79 begin_frame_source_(nullptr),
81 routing_id_(contents
->GetRoutingID()),
82 input_handler_(nullptr),
83 registered_with_client_(false),
85 renderer_needs_begin_frames_(false),
86 need_animate_input_(false),
87 weak_ptr_factory_(this) {
89 DCHECK_NE(routing_id_
, MSG_ROUTING_NONE
);
92 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
93 DCHECK(!output_surface_
);
94 DCHECK(!begin_frame_source_
);
95 DCHECK(!input_handler_
);
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(
109 compositor_client_
= compositor_client
;
111 // SetClient is essentially the constructor and destructor of
112 // SynchronousCompositorImpl.
113 if (compositor_client_
) {
114 SynchronousCompositorRegistry::GetInstance()->RegisterCompositor(
119 void SynchronousCompositorImpl::RegisterWithClient() {
120 DCHECK(CalledOnValidThread());
121 DCHECK(compositor_client_
);
122 DCHECK(output_surface_
);
123 DCHECK(input_handler_
);
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 // Setting the delegate causes UpdateRootLayerState immediately so do it
134 // after setting the client.
135 input_handler_
->SetRootLayerScrollOffsetDelegate(this);
136 // This disables the input system from animating inputs autonomously, instead
137 // routing all input animations through the SynchronousInputHandler, which is
139 synchronous_input_handler_proxy_
->SetOnlySynchronouslyAnimateRootFlings(this);
143 void SynchronousCompositor::SetGpuService(
144 scoped_refptr
<gpu::InProcessCommandBuffer::Service
> service
) {
145 g_factory
.Get().SetDeferredGpuService(service
);
146 GpuProcessHost::RegisterGpuMainThreadFactory(
147 CreateInProcessGpuThreadForSynchronousCompositor
);
151 void SynchronousCompositor::SetUseIpcCommandBuffer() {
152 g_factory
.Get().SetUseIpcCommandBuffer();
155 void SynchronousCompositorImpl::DidInitializeRendererObjects(
156 SynchronousCompositorOutputSurface
* output_surface
,
157 SynchronousCompositorExternalBeginFrameSource
* begin_frame_source
,
158 cc::InputHandler
* input_handler
,
159 SynchronousInputHandlerProxy
* synchronous_input_handler_proxy
) {
160 DCHECK(!output_surface_
);
161 DCHECK(!begin_frame_source_
);
162 DCHECK(output_surface
);
163 DCHECK(begin_frame_source
);
164 DCHECK(compositor_client_
);
165 DCHECK(input_handler
);
166 DCHECK(synchronous_input_handler_proxy
);
168 output_surface_
= output_surface
;
169 begin_frame_source_
= begin_frame_source
;
170 input_handler_
= input_handler
;
171 synchronous_input_handler_proxy_
= synchronous_input_handler_proxy
;
173 output_surface_
->SetCompositor(this);
174 begin_frame_source_
->SetCompositor(this);
177 void SynchronousCompositorImpl::DidDestroyRendererObjects() {
178 DCHECK(output_surface_
);
179 DCHECK(begin_frame_source_
);
180 DCHECK(compositor_client_
);
182 if (registered_with_client_
) {
183 input_handler_
->SetRootLayerScrollOffsetDelegate(nullptr);
184 output_surface_
->SetTreeActivationCallback(base::Closure());
185 compositor_client_
->DidDestroyCompositor(this);
186 registered_with_client_
= false;
189 begin_frame_source_
->SetCompositor(nullptr);
190 output_surface_
->SetCompositor(nullptr);
192 input_handler_
= nullptr;
193 begin_frame_source_
= nullptr;
194 output_surface_
= nullptr;
195 // Don't propogate this signal from one renderer to the next.
196 need_animate_input_
= false;
199 scoped_ptr
<cc::CompositorFrame
> SynchronousCompositorImpl::DemandDrawHw(
200 gfx::Size surface_size
,
201 const gfx::Transform
& transform
,
204 gfx::Rect viewport_rect_for_tile_priority
,
205 const gfx::Transform
& transform_for_tile_priority
) {
206 DCHECK(CalledOnValidThread());
207 DCHECK(output_surface_
);
208 DCHECK(compositor_client_
);
209 DCHECK(begin_frame_source_
);
211 scoped_ptr
<cc::CompositorFrame
> frame
=
212 output_surface_
->DemandDrawHw(surface_size
,
216 viewport_rect_for_tile_priority
,
217 transform_for_tile_priority
);
220 UpdateFrameMetaData(frame
->metadata
);
225 void SynchronousCompositorImpl::ReturnResources(
226 const cc::CompositorFrameAck
& frame_ack
) {
227 DCHECK(CalledOnValidThread());
228 output_surface_
->ReturnResources(frame_ack
);
231 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas
* canvas
) {
232 DCHECK(CalledOnValidThread());
233 DCHECK(output_surface_
);
234 DCHECK(compositor_client_
);
235 DCHECK(begin_frame_source_
);
237 scoped_ptr
<cc::CompositorFrame
> frame
=
238 output_surface_
->DemandDrawSw(canvas
);
241 UpdateFrameMetaData(frame
->metadata
);
243 return !!frame
.get();
246 void SynchronousCompositorImpl::UpdateFrameMetaData(
247 const cc::CompositorFrameMetadata
& frame_metadata
) {
248 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
249 contents_
->GetRenderWidgetHostView());
251 rwhv
->SynchronousFrameMetadata(frame_metadata
);
255 void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit
) {
256 DCHECK(CalledOnValidThread());
257 DCHECK(output_surface_
);
259 size_t current_bytes_limit
= output_surface_
->GetMemoryPolicy();
260 output_surface_
->SetMemoryPolicy(bytes_limit
);
262 if (bytes_limit
&& !current_bytes_limit
) {
263 g_factory
.Get().CompositorInitializedHardwareDraw();
264 } else if (!bytes_limit
&& current_bytes_limit
) {
265 g_factory
.Get().CompositorReleasedHardwareDraw();
269 void SynchronousCompositorImpl::PostInvalidate() {
270 DCHECK(CalledOnValidThread());
271 DCHECK(compositor_client_
);
272 if (registered_with_client_
)
273 compositor_client_
->PostInvalidate();
276 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset(
277 const gfx::ScrollOffset
& root_offset
) {
278 DCHECK(CalledOnValidThread());
281 input_handler_
->OnRootLayerDelegatedScrollOffsetChanged(root_offset
);
284 void SynchronousCompositorImpl::SetIsActive(bool is_active
) {
285 TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active",
287 is_active_
= is_active
;
288 UpdateNeedsBeginFrames();
291 void SynchronousCompositorImpl::OnComputeScroll(
292 base::TimeTicks animation_time
) {
293 if (need_animate_input_
) {
294 need_animate_input_
= false;
295 synchronous_input_handler_proxy_
->SynchronouslyAnimate(animation_time
);
299 void SynchronousCompositorImpl::OnNeedsBeginFramesChange(
300 bool needs_begin_frames
) {
301 renderer_needs_begin_frames_
= needs_begin_frames
;
302 UpdateNeedsBeginFrames();
305 void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs
& args
) {
306 if (!registered_with_client_
&& is_active_
&& renderer_needs_begin_frames_
) {
307 // Make sure this is a BeginFrame that renderer side explicitly requested.
308 // Otherwise it is possible renderer objects not initialized.
309 RegisterWithClient();
310 DCHECK(registered_with_client_
);
312 if (begin_frame_source_
)
313 begin_frame_source_
->BeginFrame(args
);
316 void SynchronousCompositorImpl::UpdateNeedsBeginFrames() {
317 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
318 contents_
->GetRenderWidgetHostView());
320 rwhv
->OnSetNeedsBeginFrames(is_active_
&& renderer_needs_begin_frames_
);
323 void SynchronousCompositorImpl::DidOverscroll(
324 const DidOverscrollParams
& params
) {
325 DCHECK(compositor_client_
);
326 if (registered_with_client_
) {
327 compositor_client_
->DidOverscroll(params
.accumulated_overscroll
,
328 params
.latest_overscroll_delta
,
329 params
.current_fling_velocity
);
333 void SynchronousCompositorImpl::DidStopFlinging() {
334 // It's important that the fling-end notification follow the same path as it
335 // takes on other platforms (using an IPC). This ensures consistent
336 // bookkeeping at all stages of the input pipeline.
337 contents_
->GetRenderProcessHost()->OnMessageReceived(
338 InputHostMsg_DidStopFlinging(routing_id_
));
341 InputEventAckState
SynchronousCompositorImpl::HandleInputEvent(
342 const blink::WebInputEvent
& input_event
) {
343 DCHECK(CalledOnValidThread());
344 return g_factory
.Get().synchronous_input_event_filter()->HandleInputEvent(
345 contents_
->GetRoutingID(), input_event
);
348 void SynchronousCompositorImpl::DeliverMessages() {
349 ScopedVector
<IPC::Message
> messages
;
350 output_surface_
->GetMessagesToDeliver(&messages
);
351 RenderProcessHost
* rph
= contents_
->GetRenderProcessHost();
352 for (ScopedVector
<IPC::Message
>::const_iterator i
= messages
.begin();
355 rph
->OnMessageReceived(**i
);
359 void SynchronousCompositorImpl::DidActivatePendingTree() {
360 DCHECK(compositor_client_
);
361 if (registered_with_client_
)
362 compositor_client_
->DidUpdateContent();
366 void SynchronousCompositorImpl::SetNeedsSynchronousAnimateInput() {
367 DCHECK(CalledOnValidThread());
368 DCHECK(compositor_client_
);
369 if (!registered_with_client_
)
371 need_animate_input_
= true;
372 compositor_client_
->PostInvalidate();
375 void SynchronousCompositorImpl::UpdateRootLayerState(
376 const gfx::ScrollOffset
& total_scroll_offset
,
377 const gfx::ScrollOffset
& max_scroll_offset
,
378 const gfx::SizeF
& scrollable_size
,
379 float page_scale_factor
,
380 float min_page_scale_factor
,
381 float max_page_scale_factor
) {
382 DCHECK(CalledOnValidThread());
383 DCHECK(compositor_client_
);
385 if (registered_with_client_
) {
386 // TODO(miletus): Pass in ScrollOffset. crbug.com/414283.
387 compositor_client_
->UpdateRootLayerState(
388 gfx::ScrollOffsetToVector2dF(total_scroll_offset
),
389 gfx::ScrollOffsetToVector2dF(max_scroll_offset
),
392 min_page_scale_factor
,
393 max_page_scale_factor
);
397 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
398 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
399 bool SynchronousCompositorImpl::CalledOnValidThread() const {
400 return BrowserThread::CurrentlyOn(BrowserThread::UI
);
404 void SynchronousCompositor::SetClientForWebContents(
405 WebContents
* contents
,
406 SynchronousCompositorClient
* client
) {
409 g_factory
.Get(); // Ensure it's initialized.
410 SynchronousCompositorImpl::CreateForWebContents(contents
);
412 SynchronousCompositorImpl
* instance
=
413 SynchronousCompositorImpl::FromWebContents(contents
);
415 instance
->SetClient(client
);
418 } // namespace content