| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "content/browser/android/in_process/synchronous_compositor_impl.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "base/auto_reset.h" | |
| 10 #include "base/bind.h" | |
| 11 #include "base/lazy_instance.h" | |
| 12 #include "base/message_loop/message_loop.h" | |
| 13 #include "content/browser/android/in_process/synchronous_compositor_factory_impl
.h" | |
| 14 #include "content/browser/android/in_process/synchronous_compositor_registry_in_
proc.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 "content/public/browser/render_widget_host.h" | |
| 25 #include "content/public/common/child_process_host.h" | |
| 26 #include "ui/gfx/geometry/scroll_offset.h" | |
| 27 #include "ui/gl/gl_surface.h" | |
| 28 | |
| 29 namespace content { | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 int g_process_id = ChildProcessHost::kInvalidUniqueID; | |
| 34 | |
| 35 base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory = | |
| 36 LAZY_INSTANCE_INITIALIZER; | |
| 37 | |
| 38 } // namespace | |
| 39 | |
| 40 SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID( | |
| 41 int routing_id) { | |
| 42 if (g_factory == nullptr) | |
| 43 return nullptr; | |
| 44 if (g_process_id == ChildProcessHost::kInvalidUniqueID) | |
| 45 return nullptr; | |
| 46 RenderViewHost* rvh = RenderViewHost::FromID(g_process_id, routing_id); | |
| 47 if (!rvh) | |
| 48 return nullptr; | |
| 49 RenderWidgetHostViewAndroid* rwhva = | |
| 50 static_cast<RenderWidgetHostViewAndroid*>(rvh->GetWidget()->GetView()); | |
| 51 if (!rwhva) | |
| 52 return nullptr; | |
| 53 return static_cast<SynchronousCompositorImpl*>( | |
| 54 rwhva->GetSynchronousCompositor()); | |
| 55 } | |
| 56 | |
| 57 SynchronousCompositorImpl::SynchronousCompositorImpl( | |
| 58 RenderWidgetHostViewAndroid* rwhva, | |
| 59 SynchronousCompositorClient* client) | |
| 60 : rwhva_(rwhva), | |
| 61 routing_id_(rwhva_->GetRenderWidgetHost()->GetRoutingID()), | |
| 62 compositor_client_(client), | |
| 63 output_surface_(nullptr), | |
| 64 begin_frame_source_(nullptr), | |
| 65 synchronous_input_handler_proxy_(nullptr), | |
| 66 registered_with_client_(false), | |
| 67 is_active_(true), | |
| 68 renderer_needs_begin_frames_(false), | |
| 69 need_animate_input_(false), | |
| 70 weak_ptr_factory_(this) { | |
| 71 DCHECK_NE(routing_id_, MSG_ROUTING_NONE); | |
| 72 g_factory.Get(); // Ensure it's initialized. | |
| 73 | |
| 74 int process_id = rwhva_->GetRenderWidgetHost()->GetProcess()->GetID(); | |
| 75 if (g_process_id == ChildProcessHost::kInvalidUniqueID) { | |
| 76 g_process_id = process_id; | |
| 77 } else { | |
| 78 DCHECK_EQ(g_process_id, process_id); // Not multiprocess compatible. | |
| 79 } | |
| 80 | |
| 81 SynchronousCompositorRegistryInProc::GetInstance()->RegisterCompositor( | |
| 82 routing_id_, this); | |
| 83 } | |
| 84 | |
| 85 SynchronousCompositorImpl::~SynchronousCompositorImpl() { | |
| 86 SynchronousCompositorRegistryInProc::GetInstance()->UnregisterCompositor( | |
| 87 routing_id_, this); | |
| 88 } | |
| 89 | |
| 90 void SynchronousCompositorImpl::RegisterWithClient() { | |
| 91 DCHECK(CalledOnValidThread()); | |
| 92 DCHECK(output_surface_); | |
| 93 DCHECK(synchronous_input_handler_proxy_); | |
| 94 DCHECK(!registered_with_client_); | |
| 95 registered_with_client_ = true; | |
| 96 | |
| 97 compositor_client_->DidInitializeCompositor(this); | |
| 98 compositor_client_->DidBecomeCurrent(this); | |
| 99 | |
| 100 output_surface_->SetTreeActivationCallback( | |
| 101 base::Bind(&SynchronousCompositorImpl::DidActivatePendingTree, | |
| 102 weak_ptr_factory_.GetWeakPtr())); | |
| 103 | |
| 104 // This disables the input system from animating inputs autonomously, instead | |
| 105 // routing all input animations through the SynchronousInputHandler, which is | |
| 106 // |this| class. Calling this causes an UpdateRootLayerState() immediately so, | |
| 107 // do it after setting the client. | |
| 108 synchronous_input_handler_proxy_->SetOnlySynchronouslyAnimateRootFlings(this); | |
| 109 } | |
| 110 | |
| 111 void SynchronousCompositorImpl::DidInitializeRendererObjects( | |
| 112 SynchronousCompositorOutputSurface* output_surface, | |
| 113 SynchronousCompositorExternalBeginFrameSource* begin_frame_source, | |
| 114 ui::SynchronousInputHandlerProxy* synchronous_input_handler_proxy) { | |
| 115 DCHECK(!output_surface_); | |
| 116 DCHECK(!begin_frame_source_); | |
| 117 DCHECK(output_surface); | |
| 118 DCHECK(begin_frame_source); | |
| 119 DCHECK(synchronous_input_handler_proxy); | |
| 120 | |
| 121 output_surface_ = output_surface; | |
| 122 begin_frame_source_ = begin_frame_source; | |
| 123 synchronous_input_handler_proxy_ = synchronous_input_handler_proxy; | |
| 124 | |
| 125 output_surface_->SetSyncClient(this); | |
| 126 begin_frame_source_->SetClient(this); | |
| 127 begin_frame_source_->SetBeginFrameSourcePaused(!is_active_); | |
| 128 } | |
| 129 | |
| 130 void SynchronousCompositorImpl::DidDestroyRendererObjects() { | |
| 131 DCHECK(output_surface_); | |
| 132 DCHECK(begin_frame_source_); | |
| 133 | |
| 134 if (registered_with_client_) { | |
| 135 output_surface_->SetTreeActivationCallback(base::Closure()); | |
| 136 compositor_client_->DidDestroyCompositor(this); | |
| 137 registered_with_client_ = false; | |
| 138 } | |
| 139 | |
| 140 // This object is being destroyed, so remove pointers to it. | |
| 141 begin_frame_source_->SetClient(nullptr); | |
| 142 output_surface_->SetSyncClient(nullptr); | |
| 143 synchronous_input_handler_proxy_->SetOnlySynchronouslyAnimateRootFlings( | |
| 144 nullptr); | |
| 145 | |
| 146 synchronous_input_handler_proxy_ = nullptr; | |
| 147 begin_frame_source_ = nullptr; | |
| 148 output_surface_ = nullptr; | |
| 149 // Don't propogate this signal from one renderer to the next. | |
| 150 need_animate_input_ = false; | |
| 151 } | |
| 152 | |
| 153 SynchronousCompositor::Frame SynchronousCompositorImpl::DemandDrawHw( | |
| 154 const gfx::Size& surface_size, | |
| 155 const gfx::Transform& transform, | |
| 156 const gfx::Rect& viewport, | |
| 157 const gfx::Rect& clip, | |
| 158 const gfx::Rect& viewport_rect_for_tile_priority, | |
| 159 const gfx::Transform& transform_for_tile_priority) { | |
| 160 DCHECK(CalledOnValidThread()); | |
| 161 DCHECK(output_surface_); | |
| 162 DCHECK(begin_frame_source_); | |
| 163 DCHECK(!frame_holder_.frame); | |
| 164 | |
| 165 output_surface_->DemandDrawHw(surface_size, transform, viewport, clip, | |
| 166 viewport_rect_for_tile_priority, | |
| 167 transform_for_tile_priority); | |
| 168 | |
| 169 if (frame_holder_.frame) | |
| 170 UpdateFrameMetaData(frame_holder_.frame->metadata); | |
| 171 | |
| 172 return std::move(frame_holder_); | |
| 173 } | |
| 174 | |
| 175 void SynchronousCompositorImpl::ReturnResources( | |
| 176 uint32_t output_surface_id, | |
| 177 const cc::CompositorFrameAck& frame_ack) { | |
| 178 DCHECK(CalledOnValidThread()); | |
| 179 output_surface_->ReturnResources(output_surface_id, frame_ack); | |
| 180 } | |
| 181 | |
| 182 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) { | |
| 183 DCHECK(CalledOnValidThread()); | |
| 184 DCHECK(output_surface_); | |
| 185 DCHECK(begin_frame_source_); | |
| 186 DCHECK(!frame_holder_.frame); | |
| 187 | |
| 188 output_surface_->DemandDrawSw(canvas); | |
| 189 | |
| 190 bool success = !!frame_holder_.frame; | |
| 191 if (frame_holder_.frame) { | |
| 192 UpdateFrameMetaData(frame_holder_.frame->metadata); | |
| 193 frame_holder_.frame.reset(); | |
| 194 } | |
| 195 | |
| 196 return success; | |
| 197 } | |
| 198 | |
| 199 void SynchronousCompositorImpl::SwapBuffers(uint32_t output_surface_id, | |
| 200 cc::CompositorFrame* frame) { | |
| 201 DCHECK(!frame_holder_.frame); | |
| 202 frame_holder_.output_surface_id = output_surface_id; | |
| 203 frame_holder_.frame.reset(new cc::CompositorFrame); | |
| 204 frame->AssignTo(frame_holder_.frame.get()); | |
| 205 } | |
| 206 | |
| 207 void SynchronousCompositorImpl::UpdateFrameMetaData( | |
| 208 const cc::CompositorFrameMetadata& frame_metadata) { | |
| 209 rwhva_->SynchronousFrameMetadata(frame_metadata); | |
| 210 DeliverMessages(); | |
| 211 } | |
| 212 | |
| 213 void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit) { | |
| 214 DCHECK(CalledOnValidThread()); | |
| 215 DCHECK(output_surface_); | |
| 216 output_surface_->SetMemoryPolicy(bytes_limit); | |
| 217 } | |
| 218 | |
| 219 void SynchronousCompositorImpl::Invalidate() { | |
| 220 DCHECK(CalledOnValidThread()); | |
| 221 if (registered_with_client_) | |
| 222 compositor_client_->PostInvalidate(); | |
| 223 } | |
| 224 | |
| 225 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset( | |
| 226 const gfx::ScrollOffset& root_offset) { | |
| 227 DCHECK(CalledOnValidThread()); | |
| 228 if (!synchronous_input_handler_proxy_) | |
| 229 return; | |
| 230 synchronous_input_handler_proxy_->SynchronouslySetRootScrollOffset( | |
| 231 root_offset); | |
| 232 } | |
| 233 | |
| 234 void SynchronousCompositorImpl::SynchronouslyZoomBy(float zoom_delta, | |
| 235 const gfx::Point& anchor) { | |
| 236 DCHECK(CalledOnValidThread()); | |
| 237 if (!synchronous_input_handler_proxy_) | |
| 238 return; | |
| 239 synchronous_input_handler_proxy_->SynchronouslyZoomBy(zoom_delta, anchor); | |
| 240 } | |
| 241 | |
| 242 void SynchronousCompositorImpl::SetIsActive(bool is_active) { | |
| 243 TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active", | |
| 244 is_active); | |
| 245 if (is_active_ == is_active) | |
| 246 return; | |
| 247 | |
| 248 is_active_ = is_active; | |
| 249 UpdateNeedsBeginFrames(); | |
| 250 if (begin_frame_source_) | |
| 251 begin_frame_source_->SetBeginFrameSourcePaused(!is_active_); | |
| 252 } | |
| 253 | |
| 254 void SynchronousCompositorImpl::OnComputeScroll( | |
| 255 base::TimeTicks animation_time) { | |
| 256 if (need_animate_input_) { | |
| 257 need_animate_input_ = false; | |
| 258 synchronous_input_handler_proxy_->SynchronouslyAnimate(animation_time); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 void SynchronousCompositorImpl::OnNeedsBeginFramesChange( | |
| 263 bool needs_begin_frames) { | |
| 264 renderer_needs_begin_frames_ = needs_begin_frames; | |
| 265 UpdateNeedsBeginFrames(); | |
| 266 } | |
| 267 | |
| 268 void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs& args) { | |
| 269 if (!registered_with_client_ && is_active_ && renderer_needs_begin_frames_) { | |
| 270 // Make sure this is a BeginFrame that renderer side explicitly requested. | |
| 271 // Otherwise it is possible renderer objects not initialized. | |
| 272 RegisterWithClient(); | |
| 273 DCHECK(registered_with_client_); | |
| 274 } | |
| 275 if (begin_frame_source_) | |
| 276 begin_frame_source_->BeginFrame(args); | |
| 277 } | |
| 278 | |
| 279 void SynchronousCompositorImpl::UpdateNeedsBeginFrames() { | |
| 280 rwhva_->OnSetNeedsBeginFrames(is_active_ && renderer_needs_begin_frames_); | |
| 281 } | |
| 282 | |
| 283 void SynchronousCompositorImpl::DidOverscrollInProcess( | |
| 284 const DidOverscrollParams& params) { | |
| 285 if (registered_with_client_) { | |
| 286 compositor_client_->DidOverscroll(params.accumulated_overscroll, | |
| 287 params.latest_overscroll_delta, | |
| 288 params.current_fling_velocity); | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 void SynchronousCompositorImpl::DidStopFlinging() { | |
| 293 // It's important that the fling-end notification follow the same path as it | |
| 294 // takes on other platforms (using an IPC). This ensures consistent | |
| 295 // bookkeeping at all stages of the input pipeline. | |
| 296 rwhva_->GetRenderWidgetHost()->GetProcess()->OnMessageReceived( | |
| 297 InputHostMsg_DidStopFlinging(routing_id_)); | |
| 298 } | |
| 299 | |
| 300 InputEventAckState SynchronousCompositorImpl::HandleInputEvent( | |
| 301 const blink::WebInputEvent& input_event) { | |
| 302 DCHECK(CalledOnValidThread()); | |
| 303 return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent( | |
| 304 routing_id_, input_event); | |
| 305 } | |
| 306 | |
| 307 void SynchronousCompositorImpl::DidOverscroll( | |
| 308 const DidOverscrollParams& params) { | |
| 309 // SynchronousCompositorImpl uses synchronous DidOverscrollInProcess for | |
| 310 // overscroll instead of this async path. | |
| 311 NOTREACHED(); | |
| 312 } | |
| 313 | |
| 314 bool SynchronousCompositorImpl::OnMessageReceived(const IPC::Message& message) { | |
| 315 NOTREACHED(); | |
| 316 return false; | |
| 317 } | |
| 318 | |
| 319 void SynchronousCompositorImpl::DidBecomeCurrent() { | |
| 320 // This is single process synchronous compositor. There is only one | |
| 321 // RenderViewHost. DidBecomeCurrent could be called before the renderer | |
| 322 // objects are initialized. So hold off calling DidBecomeCurrent until | |
| 323 // RegisterWithClient. Intentional no-op here. | |
| 324 } | |
| 325 | |
| 326 void SynchronousCompositorImpl::DeliverMessages() { | |
| 327 std::vector<std::unique_ptr<IPC::Message>> messages; | |
| 328 output_surface_->GetMessagesToDeliver(&messages); | |
| 329 RenderProcessHost* rph = rwhva_->GetRenderWidgetHost()->GetProcess(); | |
| 330 for (const auto& msg : messages) { | |
| 331 rph->OnMessageReceived(*msg); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 void SynchronousCompositorImpl::DidActivatePendingTree() { | |
| 336 if (registered_with_client_) | |
| 337 compositor_client_->DidUpdateContent(); | |
| 338 DeliverMessages(); | |
| 339 } | |
| 340 | |
| 341 void SynchronousCompositorImpl::SetNeedsSynchronousAnimateInput() { | |
| 342 DCHECK(CalledOnValidThread()); | |
| 343 if (!registered_with_client_) | |
| 344 return; | |
| 345 need_animate_input_ = true; | |
| 346 compositor_client_->PostInvalidate(); | |
| 347 } | |
| 348 | |
| 349 void SynchronousCompositorImpl::UpdateRootLayerState( | |
| 350 const gfx::ScrollOffset& total_scroll_offset, | |
| 351 const gfx::ScrollOffset& max_scroll_offset, | |
| 352 const gfx::SizeF& scrollable_size, | |
| 353 float page_scale_factor, | |
| 354 float min_page_scale_factor, | |
| 355 float max_page_scale_factor) { | |
| 356 DCHECK(CalledOnValidThread()); | |
| 357 | |
| 358 if (registered_with_client_) { | |
| 359 // TODO(miletus): Pass in ScrollOffset. crbug.com/414283. | |
| 360 compositor_client_->UpdateRootLayerState( | |
| 361 gfx::ScrollOffsetToVector2dF(total_scroll_offset), | |
| 362 gfx::ScrollOffsetToVector2dF(max_scroll_offset), | |
| 363 scrollable_size, | |
| 364 page_scale_factor, | |
| 365 min_page_scale_factor, | |
| 366 max_page_scale_factor); | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 // Not using base::NonThreadSafe as we want to enforce a more exacting threading | |
| 371 // requirement: SynchronousCompositorImpl() must only be used on the UI thread. | |
| 372 bool SynchronousCompositorImpl::CalledOnValidThread() const { | |
| 373 return BrowserThread::CurrentlyOn(BrowserThread::UI); | |
| 374 } | |
| 375 | |
| 376 } // namespace content | |
| OLD | NEW |