Home | History | Annotate | Download | only in compositor
      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