Home | History | Annotate | Download | only in gpu
      1 // Copyright (c) 2012 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/gpu/browser_gpu_channel_host_factory.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/threading/thread_restrictions.h"
      9 #include "content/browser/gpu/gpu_data_manager_impl.h"
     10 #include "content/browser/gpu/gpu_process_host.h"
     11 #include "content/browser/gpu/gpu_surface_tracker.h"
     12 #include "content/common/gpu/gpu_messages.h"
     13 #include "content/common/child_process_host_impl.h"
     14 #include "content/public/browser/browser_thread.h"
     15 #include "content/public/common/content_client.h"
     16 #include "ipc/ipc_forwarding_message_filter.h"
     17 
     18 namespace content {
     19 
     20 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
     21 
     22 BrowserGpuChannelHostFactory::CreateRequest::CreateRequest()
     23     : event(false, false),
     24       gpu_host_id(0),
     25       route_id(MSG_ROUTING_NONE) {
     26 }
     27 
     28 BrowserGpuChannelHostFactory::CreateRequest::~CreateRequest() {
     29 }
     30 
     31 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
     32     CauseForGpuLaunch cause)
     33     : event(false, false),
     34       cause_for_gpu_launch(cause),
     35       gpu_host_id(0),
     36       reused_gpu_process(true) {
     37 }
     38 
     39 BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() {
     40 }
     41 
     42 void BrowserGpuChannelHostFactory::Initialize() {
     43   instance_ = new BrowserGpuChannelHostFactory();
     44 }
     45 
     46 void BrowserGpuChannelHostFactory::Terminate() {
     47   delete instance_;
     48   instance_ = NULL;
     49 }
     50 
     51 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
     52     : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
     53       shutdown_event_(new base::WaitableEvent(true, false)),
     54       gpu_host_id_(0) {
     55 }
     56 
     57 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
     58   shutdown_event_->Signal();
     59 }
     60 
     61 bool BrowserGpuChannelHostFactory::IsMainThread() {
     62   return BrowserThread::CurrentlyOn(BrowserThread::UI);
     63 }
     64 
     65 base::MessageLoop* BrowserGpuChannelHostFactory::GetMainLoop() {
     66   return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI);
     67 }
     68 
     69 scoped_refptr<base::MessageLoopProxy>
     70 BrowserGpuChannelHostFactory::GetIOLoopProxy() {
     71   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
     72 }
     73 
     74 base::WaitableEvent* BrowserGpuChannelHostFactory::GetShutDownEvent() {
     75   return shutdown_event_.get();
     76 }
     77 
     78 scoped_ptr<base::SharedMemory>
     79 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
     80   scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
     81   if (!shm->CreateAnonymous(size))
     82     return scoped_ptr<base::SharedMemory>();
     83   return shm.Pass();
     84 }
     85 
     86 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
     87     CreateRequest* request,
     88     int32 surface_id,
     89     const GPUCreateCommandBufferConfig& init_params) {
     90   GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
     91   if (!host) {
     92     request->event.Signal();
     93     return;
     94   }
     95 
     96   gfx::GLSurfaceHandle surface =
     97       GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
     98 
     99   host->CreateViewCommandBuffer(
    100       surface,
    101       surface_id,
    102       gpu_client_id_,
    103       init_params,
    104       base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
    105                  request));
    106 }
    107 
    108 // static
    109 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
    110     CreateRequest* request, int32 route_id) {
    111   request->route_id = route_id;
    112   request->event.Signal();
    113 }
    114 
    115 int32 BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
    116       int32 surface_id,
    117       const GPUCreateCommandBufferConfig& init_params) {
    118   CreateRequest request;
    119   GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
    120         &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
    121         base::Unretained(this),
    122         &request,
    123         surface_id,
    124         init_params));
    125   // We're blocking the UI thread, which is generally undesirable.
    126   // In this case we need to wait for this before we can show any UI /anyway/,
    127   // so it won't cause additional jank.
    128   // TODO(piman): Make this asynchronous (http://crbug.com/125248).
    129   base::ThreadRestrictions::ScopedAllowWait allow_wait;
    130   request.event.Wait();
    131   return request.route_id;
    132 }
    133 
    134 void BrowserGpuChannelHostFactory::CreateImageOnIO(
    135     gfx::PluginWindowHandle window,
    136     int32 image_id,
    137     const CreateImageCallback& callback) {
    138   GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
    139   if (!host) {
    140     ImageCreatedOnIO(callback, gfx::Size());
    141     return;
    142   }
    143 
    144   host->CreateImage(
    145       window,
    146       gpu_client_id_,
    147       image_id,
    148       base::Bind(&BrowserGpuChannelHostFactory::ImageCreatedOnIO, callback));
    149 }
    150 
    151 // static
    152 void BrowserGpuChannelHostFactory::ImageCreatedOnIO(
    153     const CreateImageCallback& callback, const gfx::Size size) {
    154   BrowserThread::PostTask(
    155       BrowserThread::UI,
    156       FROM_HERE,
    157       base::Bind(&BrowserGpuChannelHostFactory::OnImageCreated,
    158                  callback, size));
    159 }
    160 
    161 // static
    162 void BrowserGpuChannelHostFactory::OnImageCreated(
    163     const CreateImageCallback& callback, const gfx::Size size) {
    164   callback.Run(size);
    165 }
    166 
    167 void BrowserGpuChannelHostFactory::CreateImage(
    168     gfx::PluginWindowHandle window,
    169     int32 image_id,
    170     const CreateImageCallback& callback) {
    171   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    172   GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
    173         &BrowserGpuChannelHostFactory::CreateImageOnIO,
    174         base::Unretained(this),
    175         window,
    176         image_id,
    177         callback));
    178 }
    179 
    180 void BrowserGpuChannelHostFactory::DeleteImageOnIO(
    181     int32 image_id, int32 sync_point) {
    182   GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
    183   if (!host) {
    184     return;
    185   }
    186 
    187   host->DeleteImage(gpu_client_id_, image_id, sync_point);
    188 }
    189 
    190 void BrowserGpuChannelHostFactory::DeleteImage(
    191     int32 image_id, int32 sync_point) {
    192   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    193   GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
    194         &BrowserGpuChannelHostFactory::DeleteImageOnIO,
    195         base::Unretained(this),
    196         image_id,
    197         sync_point));
    198 }
    199 
    200 void BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO(
    201     EstablishRequest* request) {
    202   GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
    203   if (!host) {
    204     host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
    205                                request->cause_for_gpu_launch);
    206     if (!host) {
    207       request->event.Signal();
    208       return;
    209     }
    210     gpu_host_id_ = host->host_id();
    211     request->reused_gpu_process = false;
    212   } else {
    213     if (host->host_id() == request->gpu_host_id) {
    214       // We come here if we retried to establish the channel because of a
    215       // failure in GpuChannelEstablishedOnIO, but we ended up with the same
    216       // process ID, meaning the failure was not because of a channel error, but
    217       // another reason. So fail now.
    218       request->event.Signal();
    219       return;
    220     }
    221     request->reused_gpu_process = true;
    222   }
    223   request->gpu_host_id = gpu_host_id_;
    224 
    225   host->EstablishGpuChannel(
    226       gpu_client_id_,
    227       true,
    228       base::Bind(&BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO,
    229                  base::Unretained(this),
    230                  request));
    231 }
    232 
    233 void BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO(
    234     EstablishRequest* request,
    235     const IPC::ChannelHandle& channel_handle,
    236     const gpu::GPUInfo& gpu_info) {
    237   if (channel_handle.name.empty() && request->reused_gpu_process) {
    238     // We failed after re-using the GPU process, but it may have died in the
    239     // mean time. Retry to have a chance to create a fresh GPU process.
    240     EstablishGpuChannelOnIO(request);
    241   } else {
    242     request->channel_handle = channel_handle;
    243     request->gpu_info = gpu_info;
    244     request->event.Signal();
    245   }
    246 }
    247 
    248 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
    249     CauseForGpuLaunch cause_for_gpu_launch) {
    250   if (gpu_channel_.get()) {
    251     // Recreate the channel if it has been lost.
    252     if (gpu_channel_->IsLost())
    253       gpu_channel_ = NULL;
    254     else
    255       return gpu_channel_.get();
    256   }
    257   // Ensure initialization on the main thread.
    258   GpuDataManagerImpl::GetInstance();
    259 
    260   EstablishRequest request(cause_for_gpu_launch);
    261   GetIOLoopProxy()->PostTask(
    262       FROM_HERE,
    263       base::Bind(
    264           &BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO,
    265           base::Unretained(this),
    266           &request));
    267 
    268   {
    269     // We're blocking the UI thread, which is generally undesirable.
    270     // In this case we need to wait for this before we can show any UI /anyway/,
    271     // so it won't cause additional jank.
    272     // TODO(piman): Make this asynchronous (http://crbug.com/125248).
    273     base::ThreadRestrictions::ScopedAllowWait allow_wait;
    274     request.event.Wait();
    275   }
    276 
    277   if (request.channel_handle.name.empty())
    278     return NULL;
    279 
    280   GetContentClient()->SetGpuInfo(request.gpu_info);
    281   gpu_channel_ = GpuChannelHost::Create(
    282       this, request.gpu_host_id, gpu_client_id_,
    283       request.gpu_info, request.channel_handle);
    284   return gpu_channel_.get();
    285 }
    286 
    287 // static
    288 void BrowserGpuChannelHostFactory::AddFilterOnIO(
    289     int host_id,
    290     scoped_refptr<IPC::ChannelProxy::MessageFilter> filter) {
    291   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    292 
    293   GpuProcessHost* host = GpuProcessHost::FromID(host_id);
    294   if (host)
    295     host->AddFilter(filter.get());
    296 }
    297 
    298 void BrowserGpuChannelHostFactory::SetHandlerForControlMessages(
    299       const uint32* message_ids,
    300       size_t num_messages,
    301       const base::Callback<void(const IPC::Message&)>& handler,
    302       base::TaskRunner* target_task_runner) {
    303   DCHECK(gpu_host_id_)
    304       << "Do not call"
    305       << " BrowserGpuChannelHostFactory::SetHandlerForControlMessages()"
    306       << " until the GpuProcessHost has been set up.";
    307 
    308   scoped_refptr<IPC::ForwardingMessageFilter> filter =
    309       new IPC::ForwardingMessageFilter(message_ids,
    310                                        num_messages,
    311                                        target_task_runner);
    312   filter->AddRoute(MSG_ROUTING_CONTROL, handler);
    313 
    314   GetIOLoopProxy()->PostTask(
    315       FROM_HERE,
    316       base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO,
    317                  gpu_host_id_,
    318                  filter));
    319 }
    320 
    321 }  // namespace content
    322