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 "base/lazy_instance.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/synchronization/lock.h" 10 #include "cc/input/input_handler.h" 11 #include "cc/input/layer_scroll_offset_delegate.h" 12 #include "content/browser/android/in_process/synchronous_input_event_filter.h" 13 #include "content/browser/renderer_host/render_widget_host_view_android.h" 14 #include "content/public/browser/android/synchronous_compositor_client.h" 15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/render_process_host.h" 17 #include "content/public/browser/render_view_host.h" 18 #include "content/renderer/android/synchronous_compositor_factory.h" 19 #include "content/renderer/media/android/stream_texture_factory_android_synchronous_impl.h" 20 #include "gpu/command_buffer/client/gl_in_process_context.h" 21 #include "gpu/command_buffer/service/stream_texture_manager_in_process_android.h" 22 #include "ui/gl/android/surface_texture_bridge.h" 23 #include "ui/gl/gl_surface.h" 24 #include "webkit/common/gpu/context_provider_in_process.h" 25 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" 26 27 namespace content { 28 29 namespace { 30 31 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; 32 33 int GetInProcessRendererId() { 34 content::RenderProcessHost::iterator it = 35 content::RenderProcessHost::AllHostsIterator(); 36 if (it.IsAtEnd()) { 37 // There should always be one RPH in single process mode. 38 NOTREACHED(); 39 return 0; 40 } 41 42 int id = it.GetCurrentValue()->GetID(); 43 it.Advance(); 44 DCHECK(it.IsAtEnd()); // Not multiprocess compatible. 45 return id; 46 } 47 48 class VideoContextProvider 49 : public StreamTextureFactorySynchronousImpl::ContextProvider { 50 public: 51 VideoContextProvider( 52 const scoped_refptr<cc::ContextProvider>& context_provider, 53 gpu::GLInProcessContext* gl_in_process_context) 54 : context_provider_(context_provider), 55 gl_in_process_context_(gl_in_process_context) {} 56 57 virtual scoped_refptr<gfx::SurfaceTextureBridge> GetSurfaceTexture( 58 uint32 stream_id) OVERRIDE { 59 return gl_in_process_context_->GetSurfaceTexture(stream_id); 60 } 61 62 virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE { 63 return context_provider_->Context3d(); 64 } 65 66 private: 67 scoped_refptr<cc::ContextProvider> context_provider_; 68 gpu::GLInProcessContext* gl_in_process_context_; 69 70 DISALLOW_COPY_AND_ASSIGN(VideoContextProvider); 71 }; 72 73 class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory { 74 public: 75 SynchronousCompositorFactoryImpl() 76 : wrapped_gl_context_for_main_thread_(NULL), 77 num_hardware_compositors_(0) { 78 SynchronousCompositorFactory::SetInstance(this); 79 } 80 81 // SynchronousCompositorFactory 82 virtual scoped_refptr<base::MessageLoopProxy> 83 GetCompositorMessageLoop() OVERRIDE { 84 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); 85 } 86 87 virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface( 88 int routing_id) OVERRIDE { 89 scoped_ptr<SynchronousCompositorOutputSurface> output_surface( 90 new SynchronousCompositorOutputSurface(routing_id)); 91 return output_surface.PassAs<cc::OutputSurface>(); 92 } 93 94 virtual InputHandlerManagerClient* GetInputHandlerManagerClient() OVERRIDE { 95 return synchronous_input_event_filter(); 96 } 97 98 SynchronousInputEventFilter* synchronous_input_event_filter() { 99 return &synchronous_input_event_filter_; 100 } 101 102 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> 103 CreateOffscreenContext() { 104 if (!gfx::GLSurface::InitializeOneOff()) 105 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(); 106 107 const char* allowed_extensions = "*"; 108 const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; 109 110 WebKit::WebGraphicsContext3D::Attributes attributes; 111 attributes.antialias = false; 112 attributes.shareResources = true; 113 attributes.noAutomaticFlushes = true; 114 115 gpu::GLInProcessContextAttribs in_process_attribs; 116 WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes( 117 attributes, &in_process_attribs); 118 scoped_ptr<gpu::GLInProcessContext> context( 119 gpu::GLInProcessContext::CreateContext(true, 120 NULL, 121 gfx::Size(1, 1), 122 attributes.shareResources, 123 allowed_extensions, 124 in_process_attribs, 125 gpu_preference)); 126 127 wrapped_gl_context_for_main_thread_ = context.get(); 128 if (!context.get()) 129 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(); 130 131 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>( 132 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext( 133 context.Pass(), attributes)); 134 } 135 136 virtual scoped_refptr<cc::ContextProvider> 137 GetOffscreenContextProviderForMainThread() OVERRIDE { 138 // This check only guarantees the main thread context is created after 139 // a compositor did successfully initialize hardware draw in the past. 140 // In particular this does not guarantee that the main thread context 141 // will fail creation when all compositors release hardware draw. 142 bool failed = !CanCreateMainThreadContext(); 143 if (!failed && 144 (!offscreen_context_for_main_thread_.get() || 145 offscreen_context_for_main_thread_->DestroyedOnMainThread())) { 146 offscreen_context_for_main_thread_ = 147 webkit::gpu::ContextProviderInProcess::Create(base::Bind( 148 &SynchronousCompositorFactoryImpl::CreateOffscreenContext, 149 base::Unretained(this))); 150 failed = !offscreen_context_for_main_thread_.get() || 151 !offscreen_context_for_main_thread_->BindToCurrentThread(); 152 } 153 154 if (failed) { 155 offscreen_context_for_main_thread_ = NULL; 156 wrapped_gl_context_for_main_thread_ = NULL; 157 } 158 return offscreen_context_for_main_thread_; 159 } 160 161 // This is called on both renderer main thread (offscreen context creation 162 // path shared between cross-process and in-process platforms) and renderer 163 // compositor impl thread (InitializeHwDraw) in order to support Android 164 // WebView synchronously enable and disable hardware mode multiple times in 165 // the same task. This is ok because in-process WGC3D creation may happen on 166 // any thread and is lightweight. 167 virtual scoped_refptr<cc::ContextProvider> 168 GetOffscreenContextProviderForCompositorThread() OVERRIDE { 169 base::AutoLock lock(offscreen_context_for_compositor_thread_lock_); 170 if (!offscreen_context_for_compositor_thread_.get() || 171 offscreen_context_for_compositor_thread_->DestroyedOnMainThread()) { 172 offscreen_context_for_compositor_thread_ = 173 webkit::gpu::ContextProviderInProcess::CreateOffscreen(); 174 } 175 return offscreen_context_for_compositor_thread_; 176 } 177 178 virtual scoped_ptr<StreamTextureFactory> CreateStreamTextureFactory( 179 int view_id) OVERRIDE { 180 scoped_ptr<StreamTextureFactorySynchronousImpl> factory( 181 new StreamTextureFactorySynchronousImpl( 182 base::Bind(&SynchronousCompositorFactoryImpl:: 183 TryCreateStreamTextureFactory, 184 base::Unretained(this)), 185 view_id)); 186 return factory.PassAs<StreamTextureFactory>(); 187 } 188 189 void CompositorInitializedHardwareDraw(SynchronousCompositorImpl* compositor); 190 void CompositorReleasedHardwareDraw(SynchronousCompositorImpl* compositor); 191 192 private: 193 void ReleaseGlobalHardwareResources(); 194 bool CanCreateMainThreadContext(); 195 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider> 196 TryCreateStreamTextureFactory(); 197 198 SynchronousInputEventFilter synchronous_input_event_filter_; 199 200 // Only guards construction and destruction of 201 // |offscreen_context_for_compositor_thread_|, not usage. 202 base::Lock offscreen_context_for_compositor_thread_lock_; 203 scoped_refptr<cc::ContextProvider> offscreen_context_for_main_thread_; 204 // This is a pointer to the context owned by 205 // |offscreen_context_for_main_thread_|. 206 gpu::GLInProcessContext* wrapped_gl_context_for_main_thread_; 207 scoped_refptr<cc::ContextProvider> offscreen_context_for_compositor_thread_; 208 209 // |num_hardware_compositor_lock_| is updated on UI thread only but can be 210 // read on renderer main thread. 211 base::Lock num_hardware_compositor_lock_; 212 unsigned int num_hardware_compositors_; 213 }; 214 215 void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw( 216 SynchronousCompositorImpl* compositor) { 217 base::AutoLock lock(num_hardware_compositor_lock_); 218 num_hardware_compositors_++; 219 } 220 221 void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw( 222 SynchronousCompositorImpl* compositor) { 223 bool should_release_resources = false; 224 { 225 base::AutoLock lock(num_hardware_compositor_lock_); 226 DCHECK_GT(num_hardware_compositors_, 0u); 227 num_hardware_compositors_--; 228 should_release_resources = num_hardware_compositors_ == 0u; 229 } 230 if (should_release_resources) 231 ReleaseGlobalHardwareResources(); 232 } 233 234 void SynchronousCompositorFactoryImpl::ReleaseGlobalHardwareResources() { 235 { 236 base::AutoLock lock(offscreen_context_for_compositor_thread_lock_); 237 offscreen_context_for_compositor_thread_ = NULL; 238 } 239 240 // TODO(boliu): Properly clean up command buffer server of main thread 241 // context here. 242 } 243 244 bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() { 245 base::AutoLock lock(num_hardware_compositor_lock_); 246 return num_hardware_compositors_ > 0; 247 } 248 249 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider> 250 SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() { 251 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider> 252 context_provider; 253 if (CanCreateMainThreadContext() && 254 GetOffscreenContextProviderForMainThread()) { 255 DCHECK(offscreen_context_for_main_thread_); 256 DCHECK(wrapped_gl_context_for_main_thread_); 257 context_provider = 258 new VideoContextProvider(offscreen_context_for_main_thread_, 259 wrapped_gl_context_for_main_thread_); 260 } 261 return context_provider; 262 } 263 264 base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory = 265 LAZY_INSTANCE_INITIALIZER; 266 267 } // namespace 268 269 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl); 270 271 // static 272 SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id, 273 int routing_id) { 274 if (g_factory == NULL) 275 return NULL; 276 RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id); 277 if (!rvh) 278 return NULL; 279 WebContents* contents = WebContents::FromRenderViewHost(rvh); 280 if (!contents) 281 return NULL; 282 return FromWebContents(contents); 283 } 284 285 SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID( 286 int routing_id) { 287 return FromID(GetInProcessRendererId(), routing_id); 288 } 289 290 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents) 291 : compositor_client_(NULL), 292 output_surface_(NULL), 293 contents_(contents), 294 input_handler_(NULL) { 295 DCHECK(contents); 296 } 297 298 SynchronousCompositorImpl::~SynchronousCompositorImpl() { 299 if (compositor_client_) 300 compositor_client_->DidDestroyCompositor(this); 301 SetInputHandler(NULL); 302 } 303 304 void SynchronousCompositorImpl::SetClient( 305 SynchronousCompositorClient* compositor_client) { 306 DCHECK(CalledOnValidThread()); 307 compositor_client_ = compositor_client; 308 } 309 310 bool SynchronousCompositorImpl::InitializeHwDraw( 311 scoped_refptr<gfx::GLSurface> surface) { 312 DCHECK(CalledOnValidThread()); 313 DCHECK(output_surface_); 314 bool success = output_surface_->InitializeHwDraw( 315 surface, 316 g_factory.Get().GetOffscreenContextProviderForCompositorThread()); 317 if (success) 318 g_factory.Get().CompositorInitializedHardwareDraw(this); 319 return success; 320 } 321 322 void SynchronousCompositorImpl::ReleaseHwDraw() { 323 DCHECK(CalledOnValidThread()); 324 DCHECK(output_surface_); 325 output_surface_->ReleaseHwDraw(); 326 g_factory.Get().CompositorReleasedHardwareDraw(this); 327 } 328 329 bool SynchronousCompositorImpl::DemandDrawHw( 330 gfx::Size surface_size, 331 const gfx::Transform& transform, 332 gfx::Rect viewport, 333 gfx::Rect clip, 334 bool stencil_enabled) { 335 DCHECK(CalledOnValidThread()); 336 DCHECK(output_surface_); 337 338 return output_surface_->DemandDrawHw( 339 surface_size, transform, viewport, clip, stencil_enabled); 340 } 341 342 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) { 343 DCHECK(CalledOnValidThread()); 344 DCHECK(output_surface_); 345 346 return output_surface_->DemandDrawSw(canvas); 347 } 348 349 void SynchronousCompositorImpl::SetMemoryPolicy( 350 const SynchronousCompositorMemoryPolicy& policy) { 351 DCHECK(CalledOnValidThread()); 352 DCHECK(output_surface_); 353 354 return output_surface_->SetMemoryPolicy(policy); 355 } 356 357 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() { 358 if (input_handler_) 359 input_handler_->OnRootLayerDelegatedScrollOffsetChanged(); 360 } 361 362 void SynchronousCompositorImpl::DidBindOutputSurface( 363 SynchronousCompositorOutputSurface* output_surface) { 364 DCHECK(CalledOnValidThread()); 365 output_surface_ = output_surface; 366 if (compositor_client_) 367 compositor_client_->DidInitializeCompositor(this); 368 } 369 370 void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface( 371 SynchronousCompositorOutputSurface* output_surface) { 372 DCHECK(CalledOnValidThread()); 373 374 // Allow for transient hand-over when two output surfaces may refer to 375 // a single delegate. 376 if (output_surface_ == output_surface) { 377 output_surface_ = NULL; 378 if (compositor_client_) 379 compositor_client_->DidDestroyCompositor(this); 380 compositor_client_ = NULL; 381 } 382 } 383 384 void SynchronousCompositorImpl::SetInputHandler( 385 cc::InputHandler* input_handler) { 386 DCHECK(CalledOnValidThread()); 387 388 if (input_handler_) 389 input_handler_->SetRootLayerScrollOffsetDelegate(NULL); 390 391 input_handler_ = input_handler; 392 393 if (input_handler_) 394 input_handler_->SetRootLayerScrollOffsetDelegate(this); 395 } 396 397 void SynchronousCompositorImpl::DidOverscroll( 398 const cc::DidOverscrollParams& params) { 399 if (compositor_client_) { 400 compositor_client_->DidOverscroll(params.accumulated_overscroll, 401 params.latest_overscroll_delta, 402 params.current_fling_velocity); 403 } 404 } 405 406 void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) { 407 DCHECK(CalledOnValidThread()); 408 if (compositor_client_) 409 compositor_client_->SetContinuousInvalidate(enable); 410 } 411 412 InputEventAckState SynchronousCompositorImpl::HandleInputEvent( 413 const WebKit::WebInputEvent& input_event) { 414 DCHECK(CalledOnValidThread()); 415 return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent( 416 contents_->GetRoutingID(), input_event); 417 } 418 419 void SynchronousCompositorImpl::UpdateFrameMetaData( 420 const cc::CompositorFrameMetadata& frame_metadata) { 421 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>( 422 contents_->GetRenderWidgetHostView()); 423 if (rwhv) 424 rwhv->SynchronousFrameMetadata(frame_metadata); 425 } 426 427 void SynchronousCompositorImpl::DidActivatePendingTree() { 428 if (compositor_client_) 429 compositor_client_->DidUpdateContent(); 430 } 431 432 void SynchronousCompositorImpl::SetMaxScrollOffset( 433 gfx::Vector2dF max_scroll_offset) { 434 DCHECK(CalledOnValidThread()); 435 if (compositor_client_) 436 compositor_client_->SetMaxRootLayerScrollOffset(max_scroll_offset); 437 } 438 439 void SynchronousCompositorImpl::SetTotalScrollOffset(gfx::Vector2dF new_value) { 440 DCHECK(CalledOnValidThread()); 441 if (compositor_client_) 442 compositor_client_->SetTotalRootLayerScrollOffset(new_value); 443 } 444 445 gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() { 446 DCHECK(CalledOnValidThread()); 447 if (compositor_client_) 448 return compositor_client_->GetTotalRootLayerScrollOffset(); 449 return gfx::Vector2dF(); 450 } 451 452 bool SynchronousCompositorImpl::IsExternalFlingActive() const { 453 DCHECK(CalledOnValidThread()); 454 if (compositor_client_) 455 return compositor_client_->IsExternalFlingActive(); 456 return false; 457 } 458 459 void SynchronousCompositorImpl::SetTotalPageScaleFactor( 460 float page_scale_factor) { 461 DCHECK(CalledOnValidThread()); 462 if (compositor_client_) 463 compositor_client_->SetRootLayerPageScaleFactor(page_scale_factor); 464 } 465 466 void SynchronousCompositorImpl::SetScrollableSize(gfx::SizeF scrollable_size) { 467 DCHECK(CalledOnValidThread()); 468 if (compositor_client_) 469 compositor_client_->SetRootLayerScrollableSize(scrollable_size); 470 } 471 472 // Not using base::NonThreadSafe as we want to enforce a more exacting threading 473 // requirement: SynchronousCompositorImpl() must only be used on the UI thread. 474 bool SynchronousCompositorImpl::CalledOnValidThread() const { 475 return BrowserThread::CurrentlyOn(BrowserThread::UI); 476 } 477 478 // static 479 void SynchronousCompositor::SetClientForWebContents( 480 WebContents* contents, 481 SynchronousCompositorClient* client) { 482 DCHECK(contents); 483 if (client) { 484 g_factory.Get(); // Ensure it's initialized. 485 SynchronousCompositorImpl::CreateForWebContents(contents); 486 } 487 if (SynchronousCompositorImpl* instance = 488 SynchronousCompositorImpl::FromWebContents(contents)) { 489 instance->SetClient(client); 490 } 491 } 492 493 } // namespace content 494