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