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