1 // Copyright (c) 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/aura/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 "cc/output/compositor_frame.h" 14 #include "cc/output/output_surface.h" 15 #include "content/browser/aura/browser_compositor_output_surface.h" 16 #include "content/browser/aura/browser_compositor_output_surface_proxy.h" 17 #include "content/browser/aura/reflector_impl.h" 18 #include "content/browser/aura/software_browser_compositor_output_surface.h" 19 #include "content/browser/gpu/browser_gpu_channel_host_factory.h" 20 #include "content/browser/gpu/gpu_data_manager_impl.h" 21 #include "content/browser/gpu/gpu_surface_tracker.h" 22 #include "content/browser/renderer_host/render_widget_host_impl.h" 23 #include "content/common/gpu/client/context_provider_command_buffer.h" 24 #include "content/common/gpu/client/gl_helper.h" 25 #include "content/common/gpu/client/gpu_channel_host.h" 26 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 27 #include "content/common/gpu/gpu_process_launch_causes.h" 28 #include "gpu/GLES2/gl2extchromium.h" 29 #include "third_party/khronos/GLES2/gl2.h" 30 #include "ui/compositor/compositor.h" 31 #include "ui/compositor/compositor_switches.h" 32 #include "ui/gfx/native_widget_types.h" 33 #include "ui/gfx/size.h" 34 35 #if defined(OS_WIN) 36 #include "content/browser/aura/software_output_device_win.h" 37 #include "ui/surface/accelerated_surface_win.h" 38 #elif defined(USE_X11) 39 #include "content/browser/aura/software_output_device_x11.h" 40 #endif 41 42 namespace content { 43 44 struct GpuProcessTransportFactory::PerCompositorData { 45 int surface_id; 46 scoped_ptr<CompositorSwapClient> swap_client; 47 #if defined(OS_WIN) 48 scoped_ptr<AcceleratedSurface> accelerated_surface; 49 #endif 50 scoped_refptr<ReflectorImpl> reflector; 51 }; 52 53 class OwnedTexture : public ui::Texture, ImageTransportFactoryObserver { 54 public: 55 OwnedTexture(WebKit::WebGraphicsContext3D* host_context, 56 const gfx::Size& size, 57 float device_scale_factor, 58 unsigned int texture_id) 59 : ui::Texture(true, size, device_scale_factor), 60 host_context_(host_context), 61 texture_id_(texture_id) { 62 ImageTransportFactory::GetInstance()->AddObserver(this); 63 } 64 65 // ui::Texture overrides: 66 virtual unsigned int PrepareTexture() OVERRIDE { 67 return texture_id_; 68 } 69 70 virtual WebKit::WebGraphicsContext3D* HostContext3D() OVERRIDE { 71 return host_context_; 72 } 73 74 // ImageTransportFactory overrides: 75 virtual void OnLostResources() OVERRIDE { 76 DeleteTexture(); 77 } 78 79 protected: 80 virtual ~OwnedTexture() { 81 ImageTransportFactory::GetInstance()->RemoveObserver(this); 82 DeleteTexture(); 83 } 84 85 protected: 86 void DeleteTexture() { 87 if (texture_id_) { 88 host_context_->deleteTexture(texture_id_); 89 texture_id_ = 0; 90 } 91 } 92 93 // A raw pointer. This |ImageTransportClientTexture| will be destroyed 94 // before the |host_context_| via 95 // |ImageTransportFactoryObserver::OnLostContext()| handlers. 96 WebKit::WebGraphicsContext3D* host_context_; 97 unsigned texture_id_; 98 99 DISALLOW_COPY_AND_ASSIGN(OwnedTexture); 100 }; 101 102 class ImageTransportClientTexture : public OwnedTexture { 103 public: 104 ImageTransportClientTexture( 105 WebKit::WebGraphicsContext3D* host_context, 106 float device_scale_factor) 107 : OwnedTexture(host_context, 108 gfx::Size(0, 0), 109 device_scale_factor, 110 host_context->createTexture()) { 111 } 112 113 virtual void Consume(const std::string& mailbox_name, 114 const gfx::Size& new_size) OVERRIDE { 115 DCHECK(mailbox_name.size() == GL_MAILBOX_SIZE_CHROMIUM); 116 mailbox_name_ = mailbox_name; 117 if (mailbox_name.empty()) 118 return; 119 120 DCHECK(host_context_ && texture_id_); 121 host_context_->bindTexture(GL_TEXTURE_2D, texture_id_); 122 host_context_->consumeTextureCHROMIUM( 123 GL_TEXTURE_2D, 124 reinterpret_cast<const signed char*>(mailbox_name.c_str())); 125 size_ = new_size; 126 host_context_->shallowFlushCHROMIUM(); 127 } 128 129 virtual std::string Produce() OVERRIDE { 130 return mailbox_name_; 131 } 132 133 protected: 134 virtual ~ImageTransportClientTexture() {} 135 136 private: 137 std::string mailbox_name_; 138 DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture); 139 }; 140 141 class CompositorSwapClient 142 : public base::SupportsWeakPtr<CompositorSwapClient>, 143 public WebGraphicsContext3DSwapBuffersClient { 144 public: 145 CompositorSwapClient(ui::Compositor* compositor, 146 GpuProcessTransportFactory* factory) 147 : compositor_(compositor), 148 factory_(factory) { 149 } 150 151 virtual ~CompositorSwapClient() { 152 } 153 154 virtual void OnViewContextSwapBuffersPosted() OVERRIDE { 155 compositor_->OnSwapBuffersPosted(); 156 } 157 158 virtual void OnViewContextSwapBuffersComplete() OVERRIDE { 159 compositor_->OnSwapBuffersComplete(); 160 } 161 162 virtual void OnViewContextSwapBuffersAborted() OVERRIDE { 163 // Recreating contexts directly from here causes issues, so post a task 164 // instead. 165 // TODO(piman): Fix the underlying issues. 166 base::MessageLoop::current()->PostTask( 167 FROM_HERE, 168 base::Bind(&CompositorSwapClient::OnLostContext, this->AsWeakPtr())); 169 } 170 171 private: 172 void OnLostContext() { 173 factory_->OnLostContext(compositor_); 174 // Note: previous line destroyed this. Don't access members from now on. 175 } 176 177 ui::Compositor* compositor_; 178 GpuProcessTransportFactory* factory_; 179 180 DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient); 181 }; 182 183 GpuProcessTransportFactory::GpuProcessTransportFactory() 184 : callback_factory_(this) { 185 output_surface_proxy_ = new BrowserCompositorOutputSurfaceProxy( 186 &output_surface_map_); 187 } 188 189 GpuProcessTransportFactory::~GpuProcessTransportFactory() { 190 DCHECK(per_compositor_data_.empty()); 191 192 // Make sure the lost context callback doesn't try to run during destruction. 193 callback_factory_.InvalidateWeakPtrs(); 194 } 195 196 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 197 GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() { 198 base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client; 199 return CreateContextCommon(swap_client, 0); 200 } 201 202 scoped_ptr<WebKit::WebGraphicsContext3D> 203 GpuProcessTransportFactory::CreateOffscreenContext() { 204 return CreateOffscreenCommandBufferContext() 205 .PassAs<WebKit::WebGraphicsContext3D>(); 206 } 207 208 scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice( 209 ui::Compositor* compositor) { 210 #if defined(OS_WIN) 211 return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceWin( 212 compositor)); 213 #elif defined(USE_X11) 214 return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceX11( 215 compositor)); 216 #endif 217 218 NOTREACHED(); 219 return scoped_ptr<cc::SoftwareOutputDevice>(); 220 } 221 222 scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface( 223 ui::Compositor* compositor) { 224 PerCompositorData* data = per_compositor_data_[compositor]; 225 if (!data) 226 data = CreatePerCompositorData(compositor); 227 228 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context; 229 CommandLine* command_line = CommandLine::ForCurrentProcess(); 230 if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing)) { 231 context = 232 CreateContextCommon(data->swap_client->AsWeakPtr(), data->surface_id); 233 } 234 if (!context) { 235 if (ui::Compositor::WasInitializedWithThread()) { 236 LOG(FATAL) << "Failed to create UI context, but can't use software " 237 " compositing with browser threaded compositing. Aborting."; 238 } 239 240 scoped_ptr<SoftwareBrowserCompositorOutputSurface> surface = 241 SoftwareBrowserCompositorOutputSurface::Create( 242 CreateSoftwareOutputDevice(compositor)); 243 return surface.PassAs<cc::OutputSurface>(); 244 } 245 246 scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner = 247 ui::Compositor::GetCompositorMessageLoop(); 248 if (!compositor_thread_task_runner.get()) 249 compositor_thread_task_runner = base::MessageLoopProxy::current(); 250 251 // Here we know the GpuProcessHost has been set up, because we created a 252 // context. 253 output_surface_proxy_->ConnectToGpuProcessHost( 254 compositor_thread_task_runner.get()); 255 256 scoped_ptr<BrowserCompositorOutputSurface> surface( 257 new BrowserCompositorOutputSurface( 258 context.PassAs<WebKit::WebGraphicsContext3D>(), 259 per_compositor_data_[compositor]->surface_id, 260 &output_surface_map_, 261 base::MessageLoopProxy::current().get(), 262 compositor->AsWeakPtr())); 263 if (data->reflector.get()) { 264 data->reflector->CreateSharedTexture(); 265 data->reflector->AttachToOutputSurface(surface.get()); 266 } 267 268 return surface.PassAs<cc::OutputSurface>(); 269 } 270 271 scoped_refptr<ui::Reflector> GpuProcessTransportFactory::CreateReflector( 272 ui::Compositor* source, 273 ui::Layer* target) { 274 PerCompositorData* data = per_compositor_data_[source]; 275 DCHECK(data); 276 277 if (data->reflector.get()) 278 RemoveObserver(data->reflector.get()); 279 280 data->reflector = new ReflectorImpl( 281 source, target, &output_surface_map_, data->surface_id); 282 AddObserver(data->reflector.get()); 283 return data->reflector; 284 } 285 286 void GpuProcessTransportFactory::RemoveReflector( 287 scoped_refptr<ui::Reflector> reflector) { 288 ReflectorImpl* reflector_impl = 289 static_cast<ReflectorImpl*>(reflector.get()); 290 PerCompositorData* data = 291 per_compositor_data_[reflector_impl->mirrored_compositor()]; 292 DCHECK(data); 293 RemoveObserver(reflector_impl); 294 data->reflector->Shutdown(); 295 data->reflector = NULL; 296 } 297 298 void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) { 299 PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor); 300 if (it == per_compositor_data_.end()) 301 return; 302 PerCompositorData* data = it->second; 303 DCHECK(data); 304 GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id); 305 delete data; 306 per_compositor_data_.erase(it); 307 if (per_compositor_data_.empty()) 308 gl_helper_.reset(); 309 } 310 311 bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; } 312 313 ui::ContextFactory* GpuProcessTransportFactory::AsContextFactory() { 314 return this; 315 } 316 317 gfx::GLSurfaceHandle GpuProcessTransportFactory::CreateSharedSurfaceHandle() { 318 CreateSharedContextLazy(); 319 if (!shared_contexts_main_thread_ || 320 !shared_contexts_main_thread_->Context3d()) 321 return gfx::GLSurfaceHandle(); 322 gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle( 323 gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT); 324 handle.parent_gpu_process_id = 325 shared_contexts_main_thread_->Context3d()->GetGPUProcessID(); 326 handle.parent_client_id = 327 shared_contexts_main_thread_->Context3d()->GetChannelID(); 328 return handle; 329 } 330 331 void GpuProcessTransportFactory::DestroySharedSurfaceHandle( 332 gfx::GLSurfaceHandle surface) {} 333 334 scoped_refptr<ui::Texture> GpuProcessTransportFactory::CreateTransportClient( 335 float device_scale_factor) { 336 if (!shared_contexts_main_thread_.get()) 337 return NULL; 338 scoped_refptr<ImageTransportClientTexture> image( 339 new ImageTransportClientTexture( 340 shared_contexts_main_thread_->Context3d(), 341 device_scale_factor)); 342 return image; 343 } 344 345 scoped_refptr<ui::Texture> GpuProcessTransportFactory::CreateOwnedTexture( 346 const gfx::Size& size, 347 float device_scale_factor, 348 unsigned int texture_id) { 349 if (!shared_contexts_main_thread_.get()) 350 return NULL; 351 scoped_refptr<OwnedTexture> image(new OwnedTexture( 352 shared_contexts_main_thread_->Context3d(), 353 size, 354 device_scale_factor, 355 texture_id)); 356 return image; 357 } 358 359 GLHelper* GpuProcessTransportFactory::GetGLHelper() { 360 if (!gl_helper_) { 361 CreateSharedContextLazy(); 362 WebGraphicsContext3DCommandBufferImpl* context_for_main_thread = 363 shared_contexts_main_thread_->Context3d(); 364 gl_helper_.reset(new GLHelper(context_for_main_thread)); 365 } 366 return gl_helper_.get(); 367 } 368 369 uint32 GpuProcessTransportFactory::InsertSyncPoint() { 370 if (!shared_contexts_main_thread_.get()) 371 return 0; 372 return shared_contexts_main_thread_->Context3d()->insertSyncPoint(); 373 } 374 375 void GpuProcessTransportFactory::WaitSyncPoint(uint32 sync_point) { 376 if (!shared_contexts_main_thread_.get()) 377 return; 378 shared_contexts_main_thread_->Context3d()->waitSyncPoint(sync_point); 379 } 380 381 void GpuProcessTransportFactory::AddObserver( 382 ImageTransportFactoryObserver* observer) { 383 observer_list_.AddObserver(observer); 384 } 385 386 void GpuProcessTransportFactory::RemoveObserver( 387 ImageTransportFactoryObserver* observer) { 388 observer_list_.RemoveObserver(observer); 389 } 390 391 scoped_refptr<cc::ContextProvider> 392 GpuProcessTransportFactory::OffscreenContextProviderForMainThread() { 393 if (!shared_contexts_main_thread_.get() || 394 shared_contexts_main_thread_->DestroyedOnMainThread()) { 395 shared_contexts_main_thread_ = ContextProviderCommandBuffer::Create( 396 base::Bind(&GpuProcessTransportFactory:: 397 CreateOffscreenCommandBufferContext, 398 base::Unretained(this))); 399 if (shared_contexts_main_thread_) { 400 shared_contexts_main_thread_->SetLostContextCallback(base::Bind( 401 &GpuProcessTransportFactory:: 402 OnLostMainThreadSharedContextInsideCallback, 403 callback_factory_.GetWeakPtr())); 404 405 if (!shared_contexts_main_thread_->BindToCurrentThread()) 406 shared_contexts_main_thread_ = NULL; 407 } 408 } 409 return shared_contexts_main_thread_; 410 } 411 412 scoped_refptr<cc::ContextProvider> 413 GpuProcessTransportFactory::OffscreenContextProviderForCompositorThread() { 414 if (!shared_contexts_compositor_thread_.get() || 415 shared_contexts_compositor_thread_->DestroyedOnMainThread()) { 416 shared_contexts_compositor_thread_ = ContextProviderCommandBuffer::Create( 417 base::Bind(&GpuProcessTransportFactory:: 418 CreateOffscreenCommandBufferContext, 419 base::Unretained(this))); 420 } 421 return shared_contexts_compositor_thread_; 422 } 423 424 void GpuProcessTransportFactory::OnLostContext(ui::Compositor* compositor) { 425 LOG(ERROR) << "Lost UI compositor context."; 426 PerCompositorData* data = per_compositor_data_[compositor]; 427 DCHECK(data); 428 429 // Prevent callbacks from other contexts in the same share group from 430 // calling us again. 431 data->swap_client.reset(new CompositorSwapClient(compositor, this)); 432 compositor->OnSwapBuffersAborted(); 433 } 434 435 GpuProcessTransportFactory::PerCompositorData* 436 GpuProcessTransportFactory::CreatePerCompositorData( 437 ui::Compositor* compositor) { 438 DCHECK(!per_compositor_data_[compositor]); 439 440 CreateSharedContextLazy(); 441 442 gfx::AcceleratedWidget widget = compositor->widget(); 443 GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get(); 444 445 PerCompositorData* data = new PerCompositorData; 446 data->surface_id = tracker->AddSurfaceForNativeWidget(widget); 447 data->swap_client.reset(new CompositorSwapClient(compositor, this)); 448 #if defined(OS_WIN) 449 if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface()) 450 data->accelerated_surface.reset(new AcceleratedSurface(widget)); 451 #endif 452 tracker->SetSurfaceHandle( 453 data->surface_id, 454 gfx::GLSurfaceHandle(widget, gfx::NATIVE_DIRECT)); 455 456 per_compositor_data_[compositor] = data; 457 458 return data; 459 } 460 461 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 462 GpuProcessTransportFactory::CreateContextCommon( 463 const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client, 464 int surface_id) { 465 if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) 466 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 467 WebKit::WebGraphicsContext3D::Attributes attrs; 468 attrs.shareResources = true; 469 attrs.depth = false; 470 attrs.stencil = false; 471 attrs.antialias = false; 472 attrs.noAutomaticFlushes = true; 473 GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance(); 474 GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon"); 475 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context( 476 new WebGraphicsContext3DCommandBufferImpl( 477 surface_id, 478 url, 479 factory, 480 swap_client)); 481 if (!context->InitializeWithDefaultBufferSizes( 482 attrs, 483 false, 484 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE)) 485 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 486 return context.Pass(); 487 } 488 489 void GpuProcessTransportFactory::CreateSharedContextLazy() { 490 scoped_refptr<cc::ContextProvider> provider = 491 OffscreenContextProviderForMainThread(); 492 } 493 494 void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() { 495 base::MessageLoop::current()->PostTask( 496 FROM_HERE, 497 base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext, 498 callback_factory_.GetWeakPtr())); 499 } 500 501 void GpuProcessTransportFactory::OnLostMainThreadSharedContext() { 502 LOG(ERROR) << "Lost UI shared context."; 503 // Keep old resources around while we call the observers, but ensure that 504 // new resources are created if needed. 505 506 scoped_refptr<ContextProviderCommandBuffer> old_contexts_main_thread = 507 shared_contexts_main_thread_; 508 shared_contexts_main_thread_ = NULL; 509 510 scoped_ptr<GLHelper> old_helper(gl_helper_.release()); 511 512 FOR_EACH_OBSERVER(ImageTransportFactoryObserver, 513 observer_list_, 514 OnLostResources()); 515 } 516 517 } // namespace content 518