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 60using cc::ContextProvider; 61using gpu::gles2::GLES2Interface; 62 63namespace content { 64 65struct GpuProcessTransportFactory::PerCompositorData { 66 int surface_id; 67 scoped_refptr<ReflectorImpl> reflector; 68 scoped_ptr<OnscreenDisplayClient> display_client; 69}; 70 71GpuProcessTransportFactory::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 90GpuProcessTransportFactory::~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 97scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 98GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() { 99 return CreateContextCommon(0); 100} 101 102scoped_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 122scoped_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 137scoped_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 261scoped_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 275void 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 286void 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 314bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; } 315 316cc::SharedBitmapManager* GpuProcessTransportFactory::GetSharedBitmapManager() { 317 return HostSharedBitmapManager::current(); 318} 319 320ui::ContextFactory* GpuProcessTransportFactory::GetContextFactory() { 321 return this; 322} 323 324base::MessageLoopProxy* GpuProcessTransportFactory::GetCompositorMessageLoop() { 325 if (!compositor_thread_) 326 return NULL; 327 return compositor_thread_->message_loop_proxy().get(); 328} 329 330gfx::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 338scoped_ptr<cc::SurfaceIdAllocator> 339GpuProcessTransportFactory::CreateSurfaceIdAllocator() { 340 return make_scoped_ptr( 341 new cc::SurfaceIdAllocator(next_surface_id_namespace_++)); 342} 343 344cc::SurfaceManager* GpuProcessTransportFactory::GetSurfaceManager() { 345 return surface_manager_.get(); 346} 347 348GLHelper* 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 359void GpuProcessTransportFactory::AddObserver( 360 ImageTransportFactoryObserver* observer) { 361 observer_list_.AddObserver(observer); 362} 363 364void GpuProcessTransportFactory::RemoveObserver( 365 ImageTransportFactoryObserver* observer) { 366 observer_list_.RemoveObserver(observer); 367} 368 369#if defined(OS_MACOSX) 370void 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 378scoped_refptr<cc::ContextProvider> 379GpuProcessTransportFactory::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 402GpuProcessTransportFactory::PerCompositorData* 403GpuProcessTransportFactory::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 421scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 422GpuProcessTransportFactory::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 453void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() { 454 base::MessageLoop::current()->PostTask( 455 FROM_HERE, 456 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext, 457 callback_factory_.GetWeakPtr())); 458} 459 460void 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