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/common/gpu/gpu_channel_manager.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "content/child/child_thread.h"
     10 #include "content/common/gpu/gpu_channel.h"
     11 #include "content/common/gpu/gpu_memory_manager.h"
     12 #include "content/common/gpu/gpu_messages.h"
     13 #include "content/common/gpu/sync_point_manager.h"
     14 #include "gpu/command_buffer/service/feature_info.h"
     15 #include "gpu/command_buffer/service/gpu_switches.h"
     16 #include "gpu/command_buffer/service/mailbox_manager.h"
     17 #include "gpu/command_buffer/service/memory_program_cache.h"
     18 #include "ui/gl/gl_bindings.h"
     19 #include "ui/gl/gl_share_group.h"
     20 
     21 namespace content {
     22 
     23 GpuChannelManager::ImageOperation::ImageOperation(
     24     int32 sync_point, base::Closure callback)
     25     : sync_point(sync_point),
     26       callback(callback) {
     27 }
     28 
     29 GpuChannelManager::ImageOperation::~ImageOperation() {
     30 }
     31 
     32 GpuChannelManager::GpuChannelManager(ChildThread* gpu_child_thread,
     33                                      GpuWatchdog* watchdog,
     34                                      base::MessageLoopProxy* io_message_loop,
     35                                      base::WaitableEvent* shutdown_event)
     36     : weak_factory_(this),
     37       io_message_loop_(io_message_loop),
     38       shutdown_event_(shutdown_event),
     39       gpu_child_thread_(gpu_child_thread),
     40       gpu_memory_manager_(
     41           this,
     42           GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit),
     43       watchdog_(watchdog),
     44       sync_point_manager_(new SyncPointManager) {
     45   DCHECK(gpu_child_thread);
     46   DCHECK(io_message_loop);
     47   DCHECK(shutdown_event);
     48 }
     49 
     50 GpuChannelManager::~GpuChannelManager() {
     51   gpu_channels_.clear();
     52   if (default_offscreen_surface_.get()) {
     53     default_offscreen_surface_->Destroy();
     54     default_offscreen_surface_ = NULL;
     55   }
     56   DCHECK(image_operations_.empty());
     57 }
     58 
     59 gpu::gles2::ProgramCache* GpuChannelManager::program_cache() {
     60   if (!program_cache_.get() &&
     61       (gfx::g_driver_gl.ext.b_ARB_get_program_binary ||
     62        gfx::g_driver_gl.ext.b_OES_get_program_binary) &&
     63       !CommandLine::ForCurrentProcess()->HasSwitch(
     64           switches::kDisableGpuProgramCache)) {
     65     program_cache_.reset(new gpu::gles2::MemoryProgramCache());
     66   }
     67   return program_cache_.get();
     68 }
     69 
     70 void GpuChannelManager::RemoveChannel(int client_id) {
     71   Send(new GpuHostMsg_DestroyChannel(client_id));
     72   gpu_channels_.erase(client_id);
     73 }
     74 
     75 int GpuChannelManager::GenerateRouteID() {
     76   static int last_id = 0;
     77   return ++last_id;
     78 }
     79 
     80 void GpuChannelManager::AddRoute(int32 routing_id, IPC::Listener* listener) {
     81   gpu_child_thread_->AddRoute(routing_id, listener);
     82 }
     83 
     84 void GpuChannelManager::RemoveRoute(int32 routing_id) {
     85   gpu_child_thread_->RemoveRoute(routing_id);
     86 }
     87 
     88 GpuChannel* GpuChannelManager::LookupChannel(int32 client_id) {
     89   GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
     90   if (iter == gpu_channels_.end())
     91     return NULL;
     92   else
     93     return iter->second.get();
     94 }
     95 
     96 bool GpuChannelManager::OnMessageReceived(const IPC::Message& msg) {
     97   bool msg_is_ok = true;
     98   bool handled = true;
     99   IPC_BEGIN_MESSAGE_MAP_EX(GpuChannelManager, msg, msg_is_ok)
    100     IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel)
    101     IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel)
    102     IPC_MESSAGE_HANDLER(GpuMsg_CreateViewCommandBuffer,
    103                         OnCreateViewCommandBuffer)
    104     IPC_MESSAGE_HANDLER(GpuMsg_CreateImage, OnCreateImage)
    105     IPC_MESSAGE_HANDLER(GpuMsg_DeleteImage, OnDeleteImage)
    106     IPC_MESSAGE_HANDLER(GpuMsg_LoadedShader, OnLoadedShader)
    107     IPC_MESSAGE_UNHANDLED(handled = false)
    108   IPC_END_MESSAGE_MAP_EX()
    109   return handled;
    110 }
    111 
    112 bool GpuChannelManager::Send(IPC::Message* msg) {
    113   return gpu_child_thread_->Send(msg);
    114 }
    115 
    116 void GpuChannelManager::OnEstablishChannel(int client_id, bool share_context) {
    117   IPC::ChannelHandle channel_handle;
    118 
    119   gfx::GLShareGroup* share_group = NULL;
    120   gpu::gles2::MailboxManager* mailbox_manager = NULL;
    121   if (share_context) {
    122     if (!share_group_.get()) {
    123       share_group_ = new gfx::GLShareGroup;
    124       DCHECK(!mailbox_manager_.get());
    125       mailbox_manager_ = new gpu::gles2::MailboxManager;
    126     }
    127     share_group = share_group_.get();
    128     mailbox_manager = mailbox_manager_.get();
    129   }
    130 
    131   scoped_refptr<GpuChannel> channel = new GpuChannel(this,
    132                                                      watchdog_,
    133                                                      share_group,
    134                                                      mailbox_manager,
    135                                                      client_id,
    136                                                      false);
    137   if (channel->Init(io_message_loop_.get(), shutdown_event_)) {
    138     gpu_channels_[client_id] = channel;
    139     channel_handle.name = channel->GetChannelName();
    140 
    141 #if defined(OS_POSIX)
    142     // On POSIX, pass the renderer-side FD. Also mark it as auto-close so
    143     // that it gets closed after it has been sent.
    144     int renderer_fd = channel->TakeRendererFileDescriptor();
    145     DCHECK_NE(-1, renderer_fd);
    146     channel_handle.socket = base::FileDescriptor(renderer_fd, true);
    147 #endif
    148   }
    149 
    150   Send(new GpuHostMsg_ChannelEstablished(channel_handle));
    151 }
    152 
    153 void GpuChannelManager::OnCloseChannel(
    154     const IPC::ChannelHandle& channel_handle) {
    155   for (GpuChannelMap::iterator iter = gpu_channels_.begin();
    156        iter != gpu_channels_.end(); ++iter) {
    157     if (iter->second->GetChannelName() == channel_handle.name) {
    158       gpu_channels_.erase(iter);
    159       return;
    160     }
    161   }
    162 }
    163 
    164 void GpuChannelManager::OnCreateViewCommandBuffer(
    165     const gfx::GLSurfaceHandle& window,
    166     int32 surface_id,
    167     int32 client_id,
    168     const GPUCreateCommandBufferConfig& init_params) {
    169   DCHECK(surface_id);
    170   int32 route_id = MSG_ROUTING_NONE;
    171 
    172   GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
    173   if (iter != gpu_channels_.end()) {
    174     iter->second->CreateViewCommandBuffer(
    175         window, surface_id, init_params, &route_id);
    176   }
    177 
    178   Send(new GpuHostMsg_CommandBufferCreated(route_id));
    179 }
    180 
    181 void GpuChannelManager::CreateImage(
    182     gfx::PluginWindowHandle window, int32 client_id, int32 image_id) {
    183   gfx::Size size;
    184 
    185   GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
    186   if (iter != gpu_channels_.end()) {
    187     iter->second->CreateImage(window, image_id, &size);
    188   }
    189 
    190   Send(new GpuHostMsg_ImageCreated(size));
    191 }
    192 
    193 void GpuChannelManager::OnCreateImage(
    194     gfx::PluginWindowHandle window, int32 client_id, int32 image_id) {
    195   DCHECK(image_id);
    196 
    197   if (image_operations_.empty()) {
    198     CreateImage(window, client_id, image_id);
    199   } else {
    200     image_operations_.push_back(
    201         new ImageOperation(0, base::Bind(&GpuChannelManager::CreateImage,
    202                                          base::Unretained(this),
    203                                          window,
    204                                          client_id,
    205                                          image_id)));
    206   }
    207 }
    208 
    209 void GpuChannelManager::DeleteImage(int32 client_id, int32 image_id) {
    210   GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
    211   if (iter != gpu_channels_.end()) {
    212     iter->second->DeleteImage(image_id);
    213   }
    214 }
    215 
    216 void GpuChannelManager::OnDeleteImage(
    217     int32 client_id, int32 image_id, int32 sync_point) {
    218   DCHECK(image_id);
    219 
    220   if (!sync_point && image_operations_.empty()) {
    221     DeleteImage(client_id, image_id);
    222   } else {
    223     image_operations_.push_back(
    224         new ImageOperation(sync_point,
    225                            base::Bind(&GpuChannelManager::DeleteImage,
    226                                       base::Unretained(this),
    227                                       client_id,
    228                                       image_id)));
    229     if (sync_point) {
    230       sync_point_manager()->AddSyncPointCallback(
    231           sync_point,
    232           base::Bind(&GpuChannelManager::OnDeleteImageSyncPointRetired,
    233                      base::Unretained(this),
    234                      image_operations_.back()));
    235     }
    236   }
    237 }
    238 
    239 void GpuChannelManager::OnDeleteImageSyncPointRetired(
    240     ImageOperation* image_operation) {
    241   // Mark operation as no longer having a pending sync point.
    242   image_operation->sync_point = 0;
    243 
    244   // De-queue operations until we reach a pending sync point.
    245   while (!image_operations_.empty()) {
    246     // Check if operation has a pending sync point.
    247     if (image_operations_.front()->sync_point)
    248       return;
    249 
    250     image_operations_.front()->callback.Run();
    251     delete image_operations_.front();
    252     image_operations_.pop_front();
    253   }
    254 }
    255 
    256 void GpuChannelManager::OnLoadedShader(std::string program_proto) {
    257   if (program_cache())
    258     program_cache()->LoadProgram(program_proto);
    259 }
    260 
    261 bool GpuChannelManager::HandleMessagesScheduled() {
    262   for (GpuChannelMap::iterator iter = gpu_channels_.begin();
    263        iter != gpu_channels_.end(); ++iter) {
    264     if (iter->second->handle_messages_scheduled())
    265       return true;
    266   }
    267   return false;
    268 }
    269 
    270 uint64 GpuChannelManager::MessagesProcessed() {
    271   uint64 messages_processed = 0;
    272 
    273   for (GpuChannelMap::iterator iter = gpu_channels_.begin();
    274        iter != gpu_channels_.end(); ++iter) {
    275     messages_processed += iter->second->messages_processed();
    276   }
    277   return messages_processed;
    278 }
    279 
    280 void GpuChannelManager::LoseAllContexts() {
    281   for (GpuChannelMap::iterator iter = gpu_channels_.begin();
    282        iter != gpu_channels_.end(); ++iter) {
    283     iter->second->MarkAllContextsLost();
    284   }
    285   base::MessageLoop::current()->PostTask(
    286       FROM_HERE,
    287       base::Bind(&GpuChannelManager::OnLoseAllContexts,
    288                  weak_factory_.GetWeakPtr()));
    289 }
    290 
    291 void GpuChannelManager::OnLoseAllContexts() {
    292   gpu_channels_.clear();
    293 }
    294 
    295 gfx::GLSurface* GpuChannelManager::GetDefaultOffscreenSurface() {
    296   if (!default_offscreen_surface_.get()) {
    297     default_offscreen_surface_ =
    298         gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(1, 1));
    299   }
    300   return default_offscreen_surface_.get();
    301 }
    302 
    303 }  // namespace content
    304