1 // Copyright 2014 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/compositor/gpu_process_transport_factory.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/command_line.h" 11 #include "base/location.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/metrics/histogram.h" 14 #include "base/threading/thread.h" 15 #include "cc/output/compositor_frame.h" 16 #include "cc/output/output_surface.h" 17 #include "cc/surfaces/surface_manager.h" 18 #include "content/browser/compositor/browser_compositor_output_surface.h" 19 #include "content/browser/compositor/browser_compositor_output_surface_proxy.h" 20 #include "content/browser/compositor/gpu_browser_compositor_output_surface.h" 21 #include "content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h" 22 #include "content/browser/compositor/onscreen_display_client.h" 23 #include "content/browser/compositor/reflector_impl.h" 24 #include "content/browser/compositor/software_browser_compositor_output_surface.h" 25 #include "content/browser/compositor/surface_display_output_surface.h" 26 #include "content/browser/gpu/browser_gpu_channel_host_factory.h" 27 #include "content/browser/gpu/compositor_util.h" 28 #include "content/browser/gpu/gpu_data_manager_impl.h" 29 #include "content/browser/gpu/gpu_surface_tracker.h" 30 #include "content/browser/renderer_host/render_widget_host_impl.h" 31 #include "content/common/gpu/client/context_provider_command_buffer.h" 32 #include "content/common/gpu/client/gl_helper.h" 33 #include "content/common/gpu/client/gpu_channel_host.h" 34 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 35 #include "content/common/gpu/gpu_process_launch_causes.h" 36 #include "content/common/host_shared_bitmap_manager.h" 37 #include "content/public/common/content_switches.h" 38 #include "gpu/GLES2/gl2extchromium.h" 39 #include "gpu/command_buffer/client/gles2_interface.h" 40 #include "gpu/command_buffer/common/mailbox.h" 41 #include "third_party/khronos/GLES2/gl2.h" 42 #include "ui/compositor/compositor.h" 43 #include "ui/compositor/compositor_constants.h" 44 #include "ui/compositor/compositor_switches.h" 45 #include "ui/gfx/native_widget_types.h" 46 #include "ui/gfx/size.h" 47 48 #if defined(OS_WIN) 49 #include "content/browser/compositor/software_output_device_win.h" 50 #elif defined(USE_OZONE) 51 #include "content/browser/compositor/overlay_candidate_validator_ozone.h" 52 #include "content/browser/compositor/software_output_device_ozone.h" 53 #include "ui/ozone/public/surface_factory_ozone.h" 54 #elif defined(USE_X11) 55 #include "content/browser/compositor/software_output_device_x11.h" 56 #elif defined(OS_MACOSX) 57 #include "content/browser/compositor/software_output_device_mac.h" 58 #endif 59 60 using cc::ContextProvider; 61 using gpu::gles2::GLES2Interface; 62 63 namespace content { 64 65 struct GpuProcessTransportFactory::PerCompositorData { 66 int surface_id; 67 scoped_refptr<ReflectorImpl> reflector; 68 scoped_ptr<OnscreenDisplayClient> display_client; 69 }; 70 71 GpuProcessTransportFactory::GpuProcessTransportFactory() 72 : next_surface_id_namespace_(1u), 73 callback_factory_(this) { 74 output_surface_proxy_ = new BrowserCompositorOutputSurfaceProxy( 75 &output_surface_map_); 76 #if defined(OS_CHROMEOS) 77 bool use_thread = !base::CommandLine::ForCurrentProcess()->HasSwitch( 78 switches::kUIDisableThreadedCompositing); 79 #else 80 bool use_thread = false; 81 #endif 82 if (use_thread) { 83 compositor_thread_.reset(new base::Thread("Browser Compositor")); 84 compositor_thread_->Start(); 85 } 86 if (UseSurfacesEnabled()) 87 surface_manager_ = make_scoped_ptr(new cc::SurfaceManager); 88 } 89 90 GpuProcessTransportFactory::~GpuProcessTransportFactory() { 91 DCHECK(per_compositor_data_.empty()); 92 93 // Make sure the lost context callback doesn't try to run during destruction. 94 callback_factory_.InvalidateWeakPtrs(); 95 } 96 97 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 98 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() { 99 return CreateContextCommon(0); 100 } 101 102 scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice( 103 ui::Compositor* compositor) { 104 #if defined(OS_WIN) 105 return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceWin( 106 compositor)); 107 #elif defined(USE_OZONE) 108 return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceOzone( 109 compositor)); 110 #elif defined(USE_X11) 111 return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceX11( 112 compositor)); 113 #elif defined(OS_MACOSX) 114 return scoped_ptr<cc::SoftwareOutputDevice>( 115 new SoftwareOutputDeviceMac(compositor)); 116 #else 117 NOTREACHED(); 118 return scoped_ptr<cc::SoftwareOutputDevice>(); 119 #endif 120 } 121 122 scoped_ptr<cc::OverlayCandidateValidator> CreateOverlayCandidateValidator( 123 gfx::AcceleratedWidget widget) { 124 #if defined(USE_OZONE) 125 ui::OverlayCandidatesOzone* overlay_candidates = 126 ui::SurfaceFactoryOzone::GetInstance()->GetOverlayCandidates(widget); 127 if (overlay_candidates && 128 base::CommandLine::ForCurrentProcess()->HasSwitch( 129 switches::kEnableHardwareOverlays)) { 130 return scoped_ptr<cc::OverlayCandidateValidator>( 131 new OverlayCandidateValidatorOzone(widget, overlay_candidates)); 132 } 133 #endif 134 return scoped_ptr<cc::OverlayCandidateValidator>(); 135 } 136 137 scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface( 138 ui::Compositor* compositor, bool software_fallback) { 139 PerCompositorData* data = per_compositor_data_[compositor]; 140 if (!data) 141 data = CreatePerCompositorData(compositor); 142 143 bool create_software_renderer = software_fallback; 144 #if defined(OS_CHROMEOS) 145 // Software fallback does not happen on Chrome OS. 146 create_software_renderer = false; 147 #elif defined(OS_WIN) 148 if (::GetProp(compositor->widget(), kForceSoftwareCompositor)) { 149 if (::RemoveProp(compositor->widget(), kForceSoftwareCompositor)) 150 create_software_renderer = true; 151 } 152 #endif 153 154 scoped_refptr<ContextProviderCommandBuffer> context_provider; 155 156 if (!create_software_renderer) { 157 context_provider = ContextProviderCommandBuffer::Create( 158 GpuProcessTransportFactory::CreateContextCommon(data->surface_id), 159 "Compositor"); 160 } 161 162 UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor", 163 !!context_provider.get()); 164 165 if (context_provider.get()) { 166 scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner = 167 GetCompositorMessageLoop(); 168 if (!compositor_thread_task_runner.get()) 169 compositor_thread_task_runner = base::MessageLoopProxy::current(); 170 171 // Here we know the GpuProcessHost has been set up, because we created a 172 // context. 173 output_surface_proxy_->ConnectToGpuProcessHost( 174 compositor_thread_task_runner.get()); 175 } 176 177 if (UseSurfacesEnabled()) { 178 // This gets a bit confusing. Here we have a ContextProvider configured to 179 // render directly to this widget. We need to make an OnscreenDisplayClient 180 // associated with this context, then return a SurfaceDisplayOutputSurface 181 // set up to draw to the display's surface. 182 cc::SurfaceManager* manager = surface_manager_.get(); 183 scoped_ptr<cc::OutputSurface> display_surface; 184 if (!context_provider.get()) { 185 display_surface = 186 make_scoped_ptr(new SoftwareBrowserCompositorOutputSurface( 187 output_surface_proxy_, 188 CreateSoftwareOutputDevice(compositor), 189 per_compositor_data_[compositor]->surface_id, 190 &output_surface_map_, 191 compositor->vsync_manager())); 192 } else { 193 display_surface = make_scoped_ptr(new GpuBrowserCompositorOutputSurface( 194 context_provider, 195 per_compositor_data_[compositor]->surface_id, 196 &output_surface_map_, 197 compositor->vsync_manager(), 198 CreateOverlayCandidateValidator(compositor->widget()))); 199 } 200 scoped_ptr<OnscreenDisplayClient> display_client(new OnscreenDisplayClient( 201 display_surface.Pass(), manager, compositor->task_runner())); 202 203 scoped_refptr<cc::ContextProvider> offscreen_context_provider; 204 if (context_provider.get()) { 205 offscreen_context_provider = ContextProviderCommandBuffer::Create( 206 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(), 207 "Offscreen-Compositor"); 208 } 209 scoped_ptr<SurfaceDisplayOutputSurface> output_surface( 210 new SurfaceDisplayOutputSurface(manager, 211 next_surface_id_namespace_++, 212 offscreen_context_provider)); 213 display_client->set_surface_output_surface(output_surface.get()); 214 output_surface->set_display(display_client->display()); 215 data->display_client = display_client.Pass(); 216 return output_surface.PassAs<cc::OutputSurface>(); 217 } 218 219 if (!context_provider.get()) { 220 if (compositor_thread_.get()) { 221 LOG(FATAL) << "Failed to create UI context, but can't use software" 222 " compositing with browser threaded compositing. Aborting."; 223 } 224 225 scoped_ptr<SoftwareBrowserCompositorOutputSurface> surface( 226 new SoftwareBrowserCompositorOutputSurface( 227 output_surface_proxy_, 228 CreateSoftwareOutputDevice(compositor), 229 per_compositor_data_[compositor]->surface_id, 230 &output_surface_map_, 231 compositor->vsync_manager())); 232 return surface.PassAs<cc::OutputSurface>(); 233 } 234 235 scoped_ptr<BrowserCompositorOutputSurface> surface; 236 #if defined(USE_OZONE) 237 if (ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) { 238 surface.reset(new GpuSurfacelessBrowserCompositorOutputSurface( 239 context_provider, 240 per_compositor_data_[compositor]->surface_id, 241 &output_surface_map_, 242 compositor->vsync_manager(), 243 CreateOverlayCandidateValidator(compositor->widget()), 244 GL_RGB8_OES)); 245 } 246 #endif 247 if (!surface) 248 surface.reset(new GpuBrowserCompositorOutputSurface( 249 context_provider, 250 per_compositor_data_[compositor]->surface_id, 251 &output_surface_map_, 252 compositor->vsync_manager(), 253 CreateOverlayCandidateValidator(compositor->widget()))); 254 255 if (data->reflector.get()) 256 data->reflector->ReattachToOutputSurfaceFromMainThread(surface.get()); 257 258 return surface.PassAs<cc::OutputSurface>(); 259 } 260 261 scoped_refptr<ui::Reflector> GpuProcessTransportFactory::CreateReflector( 262 ui::Compositor* source, 263 ui::Layer* target) { 264 PerCompositorData* data = per_compositor_data_[source]; 265 DCHECK(data); 266 267 data->reflector = new ReflectorImpl(source, 268 target, 269 &output_surface_map_, 270 GetCompositorMessageLoop(), 271 data->surface_id); 272 return data->reflector; 273 } 274 275 void GpuProcessTransportFactory::RemoveReflector( 276 scoped_refptr<ui::Reflector> reflector) { 277 ReflectorImpl* reflector_impl = 278 static_cast<ReflectorImpl*>(reflector.get()); 279 PerCompositorData* data = 280 per_compositor_data_[reflector_impl->mirrored_compositor()]; 281 DCHECK(data); 282 data->reflector->Shutdown(); 283 data->reflector = NULL; 284 } 285 286 void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) { 287 PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor); 288 if (it == per_compositor_data_.end()) 289 return; 290 PerCompositorData* data = it->second; 291 DCHECK(data); 292 GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id); 293 delete data; 294 per_compositor_data_.erase(it); 295 if (per_compositor_data_.empty()) { 296 // Destroying the GLHelper may cause some async actions to be cancelled, 297 // causing things to request a new GLHelper. Due to crbug.com/176091 the 298 // GLHelper created in this case would be lost/leaked if we just reset() 299 // on the |gl_helper_| variable directly. So instead we call reset() on a 300 // local scoped_ptr. 301 scoped_ptr<GLHelper> helper = gl_helper_.Pass(); 302 303 // If there are any observer left at this point, make sure they clean up 304 // before we destroy the GLHelper. 305 FOR_EACH_OBSERVER( 306 ImageTransportFactoryObserver, observer_list_, OnLostResources()); 307 308 helper.reset(); 309 DCHECK(!gl_helper_) << "Destroying the GLHelper should not cause a new " 310 "GLHelper to be created."; 311 } 312 } 313 314 bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; } 315 316 cc::SharedBitmapManager* GpuProcessTransportFactory::GetSharedBitmapManager() { 317 return HostSharedBitmapManager::current(); 318 } 319 320 ui::ContextFactory* GpuProcessTransportFactory::GetContextFactory() { 321 return this; 322 } 323 324 base::MessageLoopProxy* GpuProcessTransportFactory::GetCompositorMessageLoop() { 325 if (!compositor_thread_) 326 return NULL; 327 return compositor_thread_->message_loop_proxy().get(); 328 } 329 330 gfx::GLSurfaceHandle GpuProcessTransportFactory::GetSharedSurfaceHandle() { 331 gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle( 332 gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT); 333 handle.parent_client_id = 334 BrowserGpuChannelHostFactory::instance()->GetGpuChannelId(); 335 return handle; 336 } 337 338 scoped_ptr<cc::SurfaceIdAllocator> 339 GpuProcessTransportFactory::CreateSurfaceIdAllocator() { 340 return make_scoped_ptr( 341 new cc::SurfaceIdAllocator(next_surface_id_namespace_++)); 342 } 343 344 cc::SurfaceManager* GpuProcessTransportFactory::GetSurfaceManager() { 345 return surface_manager_.get(); 346 } 347 348 GLHelper* GpuProcessTransportFactory::GetGLHelper() { 349 if (!gl_helper_ && !per_compositor_data_.empty()) { 350 scoped_refptr<cc::ContextProvider> provider = 351 SharedMainThreadContextProvider(); 352 if (provider.get()) 353 gl_helper_.reset(new GLHelper(provider->ContextGL(), 354 provider->ContextSupport())); 355 } 356 return gl_helper_.get(); 357 } 358 359 void GpuProcessTransportFactory::AddObserver( 360 ImageTransportFactoryObserver* observer) { 361 observer_list_.AddObserver(observer); 362 } 363 364 void GpuProcessTransportFactory::RemoveObserver( 365 ImageTransportFactoryObserver* observer) { 366 observer_list_.RemoveObserver(observer); 367 } 368 369 #if defined(OS_MACOSX) 370 void GpuProcessTransportFactory::OnSurfaceDisplayed(int surface_id) { 371 BrowserCompositorOutputSurface* surface = output_surface_map_.Lookup( 372 surface_id); 373 if (surface) 374 surface->OnSurfaceDisplayed(); 375 } 376 #endif 377 378 scoped_refptr<cc::ContextProvider> 379 GpuProcessTransportFactory::SharedMainThreadContextProvider() { 380 if (shared_main_thread_contexts_.get()) 381 return shared_main_thread_contexts_; 382 383 // In threaded compositing mode, we have to create our own context for the 384 // main thread since the compositor's context will be bound to the 385 // compositor thread. When not in threaded mode, we still need a separate 386 // context so that skia and gl_helper don't step on each other. 387 shared_main_thread_contexts_ = ContextProviderCommandBuffer::Create( 388 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(), 389 "Offscreen-MainThread"); 390 391 if (shared_main_thread_contexts_.get()) { 392 shared_main_thread_contexts_->SetLostContextCallback( 393 base::Bind(&GpuProcessTransportFactory:: 394 OnLostMainThreadSharedContextInsideCallback, 395 callback_factory_.GetWeakPtr())); 396 if (!shared_main_thread_contexts_->BindToCurrentThread()) 397 shared_main_thread_contexts_ = NULL; 398 } 399 return shared_main_thread_contexts_; 400 } 401 402 GpuProcessTransportFactory::PerCompositorData* 403 GpuProcessTransportFactory::CreatePerCompositorData( 404 ui::Compositor* compositor) { 405 DCHECK(!per_compositor_data_[compositor]); 406 407 gfx::AcceleratedWidget widget = compositor->widget(); 408 GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get(); 409 410 PerCompositorData* data = new PerCompositorData; 411 data->surface_id = tracker->AddSurfaceForNativeWidget(widget); 412 tracker->SetSurfaceHandle( 413 data->surface_id, 414 gfx::GLSurfaceHandle(widget, gfx::NATIVE_DIRECT)); 415 416 per_compositor_data_[compositor] = data; 417 418 return data; 419 } 420 421 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 422 GpuProcessTransportFactory::CreateContextCommon(int surface_id) { 423 if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) 424 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 425 blink::WebGraphicsContext3D::Attributes attrs; 426 attrs.shareResources = true; 427 attrs.depth = false; 428 attrs.stencil = false; 429 attrs.antialias = false; 430 attrs.noAutomaticFlushes = true; 431 bool lose_context_when_out_of_memory = true; 432 CauseForGpuLaunch cause = 433 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE; 434 scoped_refptr<GpuChannelHost> gpu_channel_host( 435 BrowserGpuChannelHostFactory::instance()->EstablishGpuChannelSync(cause)); 436 if (!gpu_channel_host.get()) { 437 LOG(ERROR) << "Failed to establish GPU channel."; 438 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 439 } 440 GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon"); 441 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context( 442 new WebGraphicsContext3DCommandBufferImpl( 443 surface_id, 444 url, 445 gpu_channel_host.get(), 446 attrs, 447 lose_context_when_out_of_memory, 448 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(), 449 NULL)); 450 return context.Pass(); 451 } 452 453 void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() { 454 base::MessageLoop::current()->PostTask( 455 FROM_HERE, 456 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext, 457 callback_factory_.GetWeakPtr())); 458 } 459 460 void GpuProcessTransportFactory::OnLostMainThreadSharedContext() { 461 LOG(ERROR) << "Lost UI shared context."; 462 463 // Keep old resources around while we call the observers, but ensure that 464 // new resources are created if needed. 465 // Kill shared contexts for both threads in tandem so they are always in 466 // the same share group. 467 scoped_refptr<cc::ContextProvider> lost_shared_main_thread_contexts = 468 shared_main_thread_contexts_; 469 shared_main_thread_contexts_ = NULL; 470 471 scoped_ptr<GLHelper> lost_gl_helper = gl_helper_.Pass(); 472 473 FOR_EACH_OBSERVER(ImageTransportFactoryObserver, 474 observer_list_, 475 OnLostResources()); 476 477 // Kill things that use the shared context before killing the shared context. 478 lost_gl_helper.reset(); 479 lost_shared_main_thread_contexts = NULL; 480 } 481 482 } // namespace content 483