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 #if defined(OS_WIN)
      6 #include <windows.h>
      7 #endif
      8 
      9 #include "content/common/gpu/gpu_channel.h"
     10 
     11 #include <queue>
     12 #include <vector>
     13 
     14 #include "base/bind.h"
     15 #include "base/command_line.h"
     16 #include "base/debug/trace_event.h"
     17 #include "base/message_loop/message_loop_proxy.h"
     18 #include "base/strings/string_util.h"
     19 #include "base/timer/timer.h"
     20 #include "content/common/gpu/devtools_gpu_agent.h"
     21 #include "content/common/gpu/gpu_channel_manager.h"
     22 #include "content/common/gpu/gpu_messages.h"
     23 #include "content/common/gpu/media/gpu_video_encode_accelerator.h"
     24 #include "content/common/gpu/sync_point_manager.h"
     25 #include "content/public/common/content_switches.h"
     26 #include "crypto/random.h"
     27 #include "gpu/command_buffer/common/mailbox.h"
     28 #include "gpu/command_buffer/service/gpu_scheduler.h"
     29 #include "gpu/command_buffer/service/image_manager.h"
     30 #include "gpu/command_buffer/service/mailbox_manager.h"
     31 #include "ipc/ipc_channel.h"
     32 #include "ipc/ipc_channel_proxy.h"
     33 #include "ui/gl/gl_context.h"
     34 #include "ui/gl/gl_image.h"
     35 #include "ui/gl/gl_surface.h"
     36 
     37 #if defined(OS_POSIX)
     38 #include "ipc/ipc_channel_posix.h"
     39 #endif
     40 
     41 #if defined(OS_ANDROID)
     42 #include "content/common/gpu/stream_texture_manager_android.h"
     43 #endif
     44 
     45 namespace content {
     46 namespace {
     47 
     48 // Number of milliseconds between successive vsync. Many GL commands block
     49 // on vsync, so thresholds for preemption should be multiples of this.
     50 const int64 kVsyncIntervalMs = 17;
     51 
     52 // Amount of time that we will wait for an IPC to be processed before
     53 // preempting. After a preemption, we must wait this long before triggering
     54 // another preemption.
     55 const int64 kPreemptWaitTimeMs = 2 * kVsyncIntervalMs;
     56 
     57 // Once we trigger a preemption, the maximum duration that we will wait
     58 // before clearing the preemption.
     59 const int64 kMaxPreemptTimeMs = kVsyncIntervalMs;
     60 
     61 // Stop the preemption once the time for the longest pending IPC drops
     62 // below this threshold.
     63 const int64 kStopPreemptThresholdMs = kVsyncIntervalMs;
     64 
     65 }  // anonymous namespace
     66 
     67 // This filter does three things:
     68 // - it counts and timestamps each message forwarded to the channel
     69 //   so that we can preempt other channels if a message takes too long to
     70 //   process. To guarantee fairness, we must wait a minimum amount of time
     71 //   before preempting and we limit the amount of time that we can preempt in
     72 //   one shot (see constants above).
     73 // - it handles the GpuCommandBufferMsg_InsertSyncPoint message on the IO
     74 //   thread, generating the sync point ID and responding immediately, and then
     75 //   posting a task to insert the GpuCommandBufferMsg_RetireSyncPoint message
     76 //   into the channel's queue.
     77 // - it generates mailbox names for clients of the GPU process on the IO thread.
     78 class GpuChannelMessageFilter : public IPC::ChannelProxy::MessageFilter {
     79  public:
     80   // Takes ownership of gpu_channel (see below).
     81   GpuChannelMessageFilter(base::WeakPtr<GpuChannel>* gpu_channel,
     82                           scoped_refptr<SyncPointManager> sync_point_manager,
     83                           scoped_refptr<base::MessageLoopProxy> message_loop)
     84       : preemption_state_(IDLE),
     85         gpu_channel_(gpu_channel),
     86         channel_(NULL),
     87         sync_point_manager_(sync_point_manager),
     88         message_loop_(message_loop),
     89         messages_forwarded_to_channel_(0),
     90         a_stub_is_descheduled_(false) {
     91   }
     92 
     93   virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE {
     94     DCHECK(!channel_);
     95     channel_ = channel;
     96   }
     97 
     98   virtual void OnFilterRemoved() OVERRIDE {
     99     DCHECK(channel_);
    100     channel_ = NULL;
    101   }
    102 
    103   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    104     DCHECK(channel_);
    105 
    106     bool handled = true;
    107     IPC_BEGIN_MESSAGE_MAP(GpuChannelMessageFilter, message)
    108       IPC_MESSAGE_HANDLER(GpuChannelMsg_GenerateMailboxNames,
    109                           OnGenerateMailboxNames)
    110       IPC_MESSAGE_HANDLER(GpuChannelMsg_GenerateMailboxNamesAsync,
    111                           OnGenerateMailboxNamesAsync)
    112       IPC_MESSAGE_UNHANDLED(handled = false)
    113     IPC_END_MESSAGE_MAP()
    114 
    115     if (message.type() == GpuCommandBufferMsg_RetireSyncPoint::ID) {
    116       // This message should not be sent explicitly by the renderer.
    117       NOTREACHED();
    118       handled = true;
    119     }
    120 
    121     // All other messages get processed by the GpuChannel.
    122     if (!handled) {
    123       messages_forwarded_to_channel_++;
    124       if (preempting_flag_.get())
    125         pending_messages_.push(PendingMessage(messages_forwarded_to_channel_));
    126       UpdatePreemptionState();
    127     }
    128 
    129     if (message.type() == GpuCommandBufferMsg_InsertSyncPoint::ID) {
    130       uint32 sync_point = sync_point_manager_->GenerateSyncPoint();
    131       IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
    132       GpuCommandBufferMsg_InsertSyncPoint::WriteReplyParams(reply, sync_point);
    133       Send(reply);
    134       message_loop_->PostTask(FROM_HERE, base::Bind(
    135           &GpuChannelMessageFilter::InsertSyncPointOnMainThread,
    136           gpu_channel_,
    137           sync_point_manager_,
    138           message.routing_id(),
    139           sync_point));
    140       handled = true;
    141     }
    142     return handled;
    143   }
    144 
    145   void MessageProcessed(uint64 messages_processed) {
    146     while (!pending_messages_.empty() &&
    147            pending_messages_.front().message_number <= messages_processed)
    148       pending_messages_.pop();
    149     UpdatePreemptionState();
    150   }
    151 
    152   void SetPreemptingFlagAndSchedulingState(
    153       gpu::PreemptionFlag* preempting_flag,
    154       bool a_stub_is_descheduled) {
    155     preempting_flag_ = preempting_flag;
    156     a_stub_is_descheduled_ = a_stub_is_descheduled;
    157   }
    158 
    159   void UpdateStubSchedulingState(bool a_stub_is_descheduled) {
    160     a_stub_is_descheduled_ = a_stub_is_descheduled;
    161     UpdatePreemptionState();
    162   }
    163 
    164   bool Send(IPC::Message* message) {
    165     return channel_->Send(message);
    166   }
    167 
    168  protected:
    169   virtual ~GpuChannelMessageFilter() {
    170     message_loop_->PostTask(FROM_HERE, base::Bind(
    171         &GpuChannelMessageFilter::DeleteWeakPtrOnMainThread, gpu_channel_));
    172   }
    173 
    174  private:
    175   // Message handlers.
    176   void OnGenerateMailboxNames(unsigned num, std::vector<gpu::Mailbox>* result) {
    177     TRACE_EVENT1("gpu", "OnGenerateMailboxNames", "num", num);
    178 
    179     result->resize(num);
    180 
    181     for (unsigned i = 0; i < num; ++i)
    182       crypto::RandBytes((*result)[i].name, sizeof((*result)[i].name));
    183   }
    184 
    185   void OnGenerateMailboxNamesAsync(unsigned num) {
    186     std::vector<gpu::Mailbox> names;
    187     OnGenerateMailboxNames(num, &names);
    188     Send(new GpuChannelMsg_GenerateMailboxNamesReply(names));
    189   }
    190 
    191   enum PreemptionState {
    192     // Either there's no other channel to preempt, there are no messages
    193     // pending processing, or we just finished preempting and have to wait
    194     // before preempting again.
    195     IDLE,
    196     // We are waiting kPreemptWaitTimeMs before checking if we should preempt.
    197     WAITING,
    198     // We can preempt whenever any IPC processing takes more than
    199     // kPreemptWaitTimeMs.
    200     CHECKING,
    201     // We are currently preempting (i.e. no stub is descheduled).
    202     PREEMPTING,
    203     // We would like to preempt, but some stub is descheduled.
    204     WOULD_PREEMPT_DESCHEDULED,
    205   };
    206 
    207   PreemptionState preemption_state_;
    208 
    209   // Maximum amount of time that we can spend in PREEMPTING.
    210   // It is reset when we transition to IDLE.
    211   base::TimeDelta max_preemption_time_;
    212 
    213   struct PendingMessage {
    214     uint64 message_number;
    215     base::TimeTicks time_received;
    216 
    217     explicit PendingMessage(uint64 message_number)
    218         : message_number(message_number),
    219           time_received(base::TimeTicks::Now()) {
    220     }
    221   };
    222 
    223   void UpdatePreemptionState() {
    224     switch (preemption_state_) {
    225       case IDLE:
    226         if (preempting_flag_.get() && !pending_messages_.empty())
    227           TransitionToWaiting();
    228         break;
    229       case WAITING:
    230         // A timer will transition us to CHECKING.
    231         DCHECK(timer_.IsRunning());
    232         break;
    233       case CHECKING:
    234         if (!pending_messages_.empty()) {
    235           base::TimeDelta time_elapsed =
    236               base::TimeTicks::Now() - pending_messages_.front().time_received;
    237           if (time_elapsed.InMilliseconds() < kPreemptWaitTimeMs) {
    238             // Schedule another check for when the IPC may go long.
    239             timer_.Start(
    240                 FROM_HERE,
    241                 base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs) -
    242                     time_elapsed,
    243                 this, &GpuChannelMessageFilter::UpdatePreemptionState);
    244           } else {
    245             if (a_stub_is_descheduled_)
    246               TransitionToWouldPreemptDescheduled();
    247             else
    248               TransitionToPreempting();
    249           }
    250         }
    251         break;
    252       case PREEMPTING:
    253         // A TransitionToIdle() timer should always be running in this state.
    254         DCHECK(timer_.IsRunning());
    255         if (a_stub_is_descheduled_)
    256           TransitionToWouldPreemptDescheduled();
    257         else
    258           TransitionToIdleIfCaughtUp();
    259         break;
    260       case WOULD_PREEMPT_DESCHEDULED:
    261         // A TransitionToIdle() timer should never be running in this state.
    262         DCHECK(!timer_.IsRunning());
    263         if (!a_stub_is_descheduled_)
    264           TransitionToPreempting();
    265         else
    266           TransitionToIdleIfCaughtUp();
    267         break;
    268       default:
    269         NOTREACHED();
    270     }
    271   }
    272 
    273   void TransitionToIdleIfCaughtUp() {
    274     DCHECK(preemption_state_ == PREEMPTING ||
    275            preemption_state_ == WOULD_PREEMPT_DESCHEDULED);
    276     if (pending_messages_.empty()) {
    277       TransitionToIdle();
    278     } else {
    279       base::TimeDelta time_elapsed =
    280           base::TimeTicks::Now() - pending_messages_.front().time_received;
    281       if (time_elapsed.InMilliseconds() < kStopPreemptThresholdMs)
    282         TransitionToIdle();
    283     }
    284   }
    285 
    286   void TransitionToIdle() {
    287     DCHECK(preemption_state_ == PREEMPTING ||
    288            preemption_state_ == WOULD_PREEMPT_DESCHEDULED);
    289     // Stop any outstanding timer set to force us from PREEMPTING to IDLE.
    290     timer_.Stop();
    291 
    292     preemption_state_ = IDLE;
    293     preempting_flag_->Reset();
    294     TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 0);
    295 
    296     UpdatePreemptionState();
    297   }
    298 
    299   void TransitionToWaiting() {
    300     DCHECK_EQ(preemption_state_, IDLE);
    301     DCHECK(!timer_.IsRunning());
    302 
    303     preemption_state_ = WAITING;
    304     timer_.Start(
    305         FROM_HERE,
    306         base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs),
    307         this, &GpuChannelMessageFilter::TransitionToChecking);
    308   }
    309 
    310   void TransitionToChecking() {
    311     DCHECK_EQ(preemption_state_, WAITING);
    312     DCHECK(!timer_.IsRunning());
    313 
    314     preemption_state_ = CHECKING;
    315     max_preemption_time_ = base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs);
    316     UpdatePreemptionState();
    317   }
    318 
    319   void TransitionToPreempting() {
    320     DCHECK(preemption_state_ == CHECKING ||
    321            preemption_state_ == WOULD_PREEMPT_DESCHEDULED);
    322     DCHECK(!a_stub_is_descheduled_);
    323 
    324     // Stop any pending state update checks that we may have queued
    325     // while CHECKING.
    326     if (preemption_state_ == CHECKING)
    327       timer_.Stop();
    328 
    329     preemption_state_ = PREEMPTING;
    330     preempting_flag_->Set();
    331     TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 1);
    332 
    333     timer_.Start(
    334        FROM_HERE,
    335        max_preemption_time_,
    336        this, &GpuChannelMessageFilter::TransitionToIdle);
    337 
    338     UpdatePreemptionState();
    339   }
    340 
    341   void TransitionToWouldPreemptDescheduled() {
    342     DCHECK(preemption_state_ == CHECKING ||
    343            preemption_state_ == PREEMPTING);
    344     DCHECK(a_stub_is_descheduled_);
    345 
    346     if (preemption_state_ == CHECKING) {
    347       // Stop any pending state update checks that we may have queued
    348       // while CHECKING.
    349       timer_.Stop();
    350     } else {
    351       // Stop any TransitionToIdle() timers that we may have queued
    352       // while PREEMPTING.
    353       timer_.Stop();
    354       max_preemption_time_ = timer_.desired_run_time() - base::TimeTicks::Now();
    355       if (max_preemption_time_ < base::TimeDelta()) {
    356         TransitionToIdle();
    357         return;
    358       }
    359     }
    360 
    361     preemption_state_ = WOULD_PREEMPT_DESCHEDULED;
    362     preempting_flag_->Reset();
    363     TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 0);
    364 
    365     UpdatePreemptionState();
    366   }
    367 
    368   static void InsertSyncPointOnMainThread(
    369       base::WeakPtr<GpuChannel>* gpu_channel,
    370       scoped_refptr<SyncPointManager> manager,
    371       int32 routing_id,
    372       uint32 sync_point) {
    373     // This function must ensure that the sync point will be retired. Normally
    374     // we'll find the stub based on the routing ID, and associate the sync point
    375     // with it, but if that fails for any reason (channel or stub already
    376     // deleted, invalid routing id), we need to retire the sync point
    377     // immediately.
    378     if (gpu_channel->get()) {
    379       GpuCommandBufferStub* stub = gpu_channel->get()->LookupCommandBuffer(
    380           routing_id);
    381       if (stub) {
    382         stub->AddSyncPoint(sync_point);
    383         GpuCommandBufferMsg_RetireSyncPoint message(routing_id, sync_point);
    384         gpu_channel->get()->OnMessageReceived(message);
    385         return;
    386       } else {
    387         gpu_channel->get()->MessageProcessed();
    388       }
    389     }
    390     manager->RetireSyncPoint(sync_point);
    391   }
    392 
    393   static void DeleteWeakPtrOnMainThread(
    394       base::WeakPtr<GpuChannel>* gpu_channel) {
    395     delete gpu_channel;
    396   }
    397 
    398   // NOTE: this is a pointer to a weak pointer. It is never dereferenced on the
    399   // IO thread, it's only passed through - therefore the WeakPtr assumptions are
    400   // respected.
    401   base::WeakPtr<GpuChannel>* gpu_channel_;
    402   IPC::Channel* channel_;
    403   scoped_refptr<SyncPointManager> sync_point_manager_;
    404   scoped_refptr<base::MessageLoopProxy> message_loop_;
    405   scoped_refptr<gpu::PreemptionFlag> preempting_flag_;
    406 
    407   std::queue<PendingMessage> pending_messages_;
    408 
    409   // Count of the number of IPCs forwarded to the GpuChannel.
    410   uint64 messages_forwarded_to_channel_;
    411 
    412   base::OneShotTimer<GpuChannelMessageFilter> timer_;
    413 
    414   bool a_stub_is_descheduled_;
    415 };
    416 
    417 GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager,
    418                        GpuWatchdog* watchdog,
    419                        gfx::GLShareGroup* share_group,
    420                        gpu::gles2::MailboxManager* mailbox,
    421                        int client_id,
    422                        bool software)
    423     : gpu_channel_manager_(gpu_channel_manager),
    424       messages_processed_(0),
    425       client_id_(client_id),
    426       share_group_(share_group ? share_group : new gfx::GLShareGroup),
    427       mailbox_manager_(mailbox ? mailbox : new gpu::gles2::MailboxManager),
    428       image_manager_(new gpu::gles2::ImageManager),
    429       watchdog_(watchdog),
    430       software_(software),
    431       handle_messages_scheduled_(false),
    432       processed_get_state_fast_(false),
    433       currently_processing_message_(NULL),
    434       weak_factory_(this),
    435       num_stubs_descheduled_(0) {
    436   DCHECK(gpu_channel_manager);
    437   DCHECK(client_id);
    438 
    439   channel_id_ = IPC::Channel::GenerateVerifiedChannelID("gpu");
    440   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    441   log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
    442   disallowed_features_.multisampling =
    443       command_line->HasSwitch(switches::kDisableGLMultisampling);
    444 #if defined(OS_ANDROID)
    445   stream_texture_manager_.reset(new StreamTextureManagerAndroid(this));
    446 #endif
    447 }
    448 
    449 
    450 bool GpuChannel::Init(base::MessageLoopProxy* io_message_loop,
    451                       base::WaitableEvent* shutdown_event) {
    452   DCHECK(!channel_.get());
    453 
    454   // Map renderer ID to a (single) channel to that process.
    455   channel_.reset(new IPC::SyncChannel(
    456       channel_id_,
    457       IPC::Channel::MODE_SERVER,
    458       this,
    459       io_message_loop,
    460       false,
    461       shutdown_event));
    462 
    463   base::WeakPtr<GpuChannel>* weak_ptr(new base::WeakPtr<GpuChannel>(
    464       weak_factory_.GetWeakPtr()));
    465 
    466   filter_ = new GpuChannelMessageFilter(
    467       weak_ptr,
    468       gpu_channel_manager_->sync_point_manager(),
    469       base::MessageLoopProxy::current());
    470   io_message_loop_ = io_message_loop;
    471   channel_->AddFilter(filter_.get());
    472 
    473   devtools_gpu_agent_.reset(new DevToolsGpuAgent(this));
    474 
    475   return true;
    476 }
    477 
    478 std::string GpuChannel::GetChannelName() {
    479   return channel_id_;
    480 }
    481 
    482 #if defined(OS_POSIX)
    483 int GpuChannel::TakeRendererFileDescriptor() {
    484   if (!channel_) {
    485     NOTREACHED();
    486     return -1;
    487   }
    488   return channel_->TakeClientFileDescriptor();
    489 }
    490 #endif  // defined(OS_POSIX)
    491 
    492 bool GpuChannel::OnMessageReceived(const IPC::Message& message) {
    493   if (log_messages_) {
    494     DVLOG(1) << "received message @" << &message << " on channel @" << this
    495              << " with type " << message.type();
    496   }
    497 
    498   if (message.type() == GpuCommandBufferMsg_GetStateFast::ID) {
    499     if (processed_get_state_fast_) {
    500       // Require a non-GetStateFast message in between two GetStateFast
    501       // messages, to ensure progress is made.
    502       std::deque<IPC::Message*>::iterator point = deferred_messages_.begin();
    503 
    504       while (point != deferred_messages_.end() &&
    505              (*point)->type() == GpuCommandBufferMsg_GetStateFast::ID) {
    506         ++point;
    507       }
    508 
    509       if (point != deferred_messages_.end()) {
    510         ++point;
    511       }
    512 
    513       deferred_messages_.insert(point, new IPC::Message(message));
    514     } else {
    515       // Move GetStateFast commands to the head of the queue, so the renderer
    516       // doesn't have to wait any longer than necessary.
    517       deferred_messages_.push_front(new IPC::Message(message));
    518     }
    519   } else {
    520     deferred_messages_.push_back(new IPC::Message(message));
    521   }
    522 
    523   OnScheduled();
    524 
    525   return true;
    526 }
    527 
    528 void GpuChannel::OnChannelError() {
    529   gpu_channel_manager_->RemoveChannel(client_id_);
    530 }
    531 
    532 bool GpuChannel::Send(IPC::Message* message) {
    533   // The GPU process must never send a synchronous IPC message to the renderer
    534   // process. This could result in deadlock.
    535   DCHECK(!message->is_sync());
    536   if (log_messages_) {
    537     DVLOG(1) << "sending message @" << message << " on channel @" << this
    538              << " with type " << message->type();
    539   }
    540 
    541   if (!channel_) {
    542     delete message;
    543     return false;
    544   }
    545 
    546   return channel_->Send(message);
    547 }
    548 
    549 void GpuChannel::RequeueMessage() {
    550   DCHECK(currently_processing_message_);
    551   deferred_messages_.push_front(
    552       new IPC::Message(*currently_processing_message_));
    553   messages_processed_--;
    554   currently_processing_message_ = NULL;
    555 }
    556 
    557 void GpuChannel::OnScheduled() {
    558   if (handle_messages_scheduled_)
    559     return;
    560   // Post a task to handle any deferred messages. The deferred message queue is
    561   // not emptied here, which ensures that OnMessageReceived will continue to
    562   // defer newly received messages until the ones in the queue have all been
    563   // handled by HandleMessage. HandleMessage is invoked as a
    564   // task to prevent reentrancy.
    565   base::MessageLoop::current()->PostTask(
    566       FROM_HERE,
    567       base::Bind(&GpuChannel::HandleMessage, weak_factory_.GetWeakPtr()));
    568   handle_messages_scheduled_ = true;
    569 }
    570 
    571 void GpuChannel::StubSchedulingChanged(bool scheduled) {
    572   bool a_stub_was_descheduled = num_stubs_descheduled_ > 0;
    573   if (scheduled) {
    574     num_stubs_descheduled_--;
    575     OnScheduled();
    576   } else {
    577     num_stubs_descheduled_++;
    578   }
    579   DCHECK_LE(num_stubs_descheduled_, stubs_.size());
    580   bool a_stub_is_descheduled = num_stubs_descheduled_ > 0;
    581 
    582   if (a_stub_is_descheduled != a_stub_was_descheduled) {
    583     if (preempting_flag_.get()) {
    584       io_message_loop_->PostTask(
    585           FROM_HERE,
    586           base::Bind(&GpuChannelMessageFilter::UpdateStubSchedulingState,
    587                      filter_,
    588                      a_stub_is_descheduled));
    589     }
    590   }
    591 }
    592 
    593 void GpuChannel::CreateViewCommandBuffer(
    594     const gfx::GLSurfaceHandle& window,
    595     int32 surface_id,
    596     const GPUCreateCommandBufferConfig& init_params,
    597     int32* route_id) {
    598   TRACE_EVENT1("gpu",
    599                "GpuChannel::CreateViewCommandBuffer",
    600                "surface_id",
    601                surface_id);
    602 
    603   *route_id = MSG_ROUTING_NONE;
    604 
    605   GpuCommandBufferStub* share_group = stubs_.Lookup(init_params.share_group_id);
    606 
    607   // Virtualize compositor contexts on OS X to prevent performance regressions
    608   // when enabling FCM.
    609   // http://crbug.com/180463
    610   bool use_virtualized_gl_context = false;
    611 #if defined(OS_MACOSX)
    612   use_virtualized_gl_context = true;
    613 #endif
    614 
    615   *route_id = GenerateRouteID();
    616   scoped_ptr<GpuCommandBufferStub> stub(
    617       new GpuCommandBufferStub(this,
    618                                share_group,
    619                                window,
    620                                mailbox_manager_.get(),
    621                                image_manager_.get(),
    622                                gfx::Size(),
    623                                disallowed_features_,
    624                                init_params.attribs,
    625                                init_params.gpu_preference,
    626                                use_virtualized_gl_context,
    627                                *route_id,
    628                                surface_id,
    629                                watchdog_,
    630                                software_,
    631                                init_params.active_url));
    632   if (preempted_flag_.get())
    633     stub->SetPreemptByFlag(preempted_flag_);
    634   router_.AddRoute(*route_id, stub.get());
    635   stubs_.AddWithID(stub.release(), *route_id);
    636 }
    637 
    638 GpuCommandBufferStub* GpuChannel::LookupCommandBuffer(int32 route_id) {
    639   return stubs_.Lookup(route_id);
    640 }
    641 
    642 void GpuChannel::CreateImage(
    643     gfx::PluginWindowHandle window,
    644     int32 image_id,
    645     gfx::Size* size) {
    646   TRACE_EVENT1("gpu",
    647                "GpuChannel::CreateImage",
    648                "image_id",
    649                image_id);
    650 
    651   *size = gfx::Size();
    652 
    653   if (image_manager_->LookupImage(image_id)) {
    654     LOG(ERROR) << "CreateImage failed, image_id already in use.";
    655     return;
    656   }
    657 
    658   scoped_refptr<gfx::GLImage> image = gfx::GLImage::CreateGLImage(window);
    659   if (!image.get())
    660     return;
    661 
    662   image_manager_->AddImage(image.get(), image_id);
    663   *size = image->GetSize();
    664 }
    665 
    666 void GpuChannel::DeleteImage(int32 image_id) {
    667   TRACE_EVENT1("gpu",
    668                "GpuChannel::DeleteImage",
    669                "image_id",
    670                image_id);
    671 
    672   image_manager_->RemoveImage(image_id);
    673 }
    674 
    675 void GpuChannel::LoseAllContexts() {
    676   gpu_channel_manager_->LoseAllContexts();
    677 }
    678 
    679 void GpuChannel::MarkAllContextsLost() {
    680   for (StubMap::Iterator<GpuCommandBufferStub> it(&stubs_);
    681        !it.IsAtEnd(); it.Advance()) {
    682     it.GetCurrentValue()->MarkContextLost();
    683   }
    684 }
    685 
    686 void GpuChannel::DestroySoon() {
    687   base::MessageLoop::current()->PostTask(
    688       FROM_HERE, base::Bind(&GpuChannel::OnDestroy, this));
    689 }
    690 
    691 int GpuChannel::GenerateRouteID() {
    692   static int last_id = 0;
    693   return ++last_id;
    694 }
    695 
    696 void GpuChannel::AddRoute(int32 route_id, IPC::Listener* listener) {
    697   router_.AddRoute(route_id, listener);
    698 }
    699 
    700 void GpuChannel::RemoveRoute(int32 route_id) {
    701   router_.RemoveRoute(route_id);
    702 }
    703 
    704 gpu::PreemptionFlag* GpuChannel::GetPreemptionFlag() {
    705   if (!preempting_flag_.get()) {
    706     preempting_flag_ = new gpu::PreemptionFlag;
    707     io_message_loop_->PostTask(
    708         FROM_HERE, base::Bind(
    709             &GpuChannelMessageFilter::SetPreemptingFlagAndSchedulingState,
    710             filter_, preempting_flag_, num_stubs_descheduled_ > 0));
    711   }
    712   return preempting_flag_.get();
    713 }
    714 
    715 void GpuChannel::SetPreemptByFlag(
    716     scoped_refptr<gpu::PreemptionFlag> preempted_flag) {
    717   preempted_flag_ = preempted_flag;
    718 
    719   for (StubMap::Iterator<GpuCommandBufferStub> it(&stubs_);
    720        !it.IsAtEnd(); it.Advance()) {
    721     it.GetCurrentValue()->SetPreemptByFlag(preempted_flag_);
    722   }
    723 }
    724 
    725 GpuChannel::~GpuChannel() {
    726   if (preempting_flag_.get())
    727     preempting_flag_->Reset();
    728 }
    729 
    730 void GpuChannel::OnDestroy() {
    731   TRACE_EVENT0("gpu", "GpuChannel::OnDestroy");
    732   gpu_channel_manager_->RemoveChannel(client_id_);
    733 }
    734 
    735 bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) {
    736   bool handled = true;
    737   IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg)
    738     IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer,
    739                         OnCreateOffscreenCommandBuffer)
    740     IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer,
    741                         OnDestroyCommandBuffer)
    742     IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateVideoEncoder, OnCreateVideoEncoder)
    743     IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyVideoEncoder,
    744                         OnDestroyVideoEncoder)
    745     IPC_MESSAGE_HANDLER(GpuChannelMsg_DevToolsStartEventsRecording,
    746                         OnDevToolsStartEventsRecording)
    747     IPC_MESSAGE_HANDLER(GpuChannelMsg_DevToolsStopEventsRecording,
    748                         OnDevToolsStopEventsRecording)
    749 #if defined(OS_ANDROID)
    750     IPC_MESSAGE_HANDLER(GpuChannelMsg_RegisterStreamTextureProxy,
    751                         OnRegisterStreamTextureProxy)
    752     IPC_MESSAGE_HANDLER(GpuChannelMsg_EstablishStreamTexture,
    753                         OnEstablishStreamTexture)
    754     IPC_MESSAGE_HANDLER(GpuChannelMsg_SetStreamTextureSize,
    755                         OnSetStreamTextureSize)
    756 #endif
    757     IPC_MESSAGE_HANDLER(
    758         GpuChannelMsg_CollectRenderingStatsForSurface,
    759         OnCollectRenderingStatsForSurface)
    760     IPC_MESSAGE_UNHANDLED(handled = false)
    761   IPC_END_MESSAGE_MAP()
    762   DCHECK(handled) << msg.type();
    763   return handled;
    764 }
    765 
    766 void GpuChannel::HandleMessage() {
    767   handle_messages_scheduled_ = false;
    768   if (deferred_messages_.empty())
    769     return;
    770 
    771   bool should_fast_track_ack = false;
    772   IPC::Message* m = deferred_messages_.front();
    773   GpuCommandBufferStub* stub = stubs_.Lookup(m->routing_id());
    774 
    775   do {
    776     if (stub) {
    777       if (!stub->IsScheduled())
    778         return;
    779       if (stub->IsPreempted()) {
    780         OnScheduled();
    781         return;
    782       }
    783     }
    784 
    785     scoped_ptr<IPC::Message> message(m);
    786     deferred_messages_.pop_front();
    787     bool message_processed = true;
    788 
    789     processed_get_state_fast_ =
    790         (message->type() == GpuCommandBufferMsg_GetStateFast::ID);
    791 
    792     currently_processing_message_ = message.get();
    793     bool result;
    794     if (message->routing_id() == MSG_ROUTING_CONTROL)
    795       result = OnControlMessageReceived(*message);
    796     else
    797       result = router_.RouteMessage(*message);
    798     currently_processing_message_ = NULL;
    799 
    800     if (!result) {
    801       // Respond to sync messages even if router failed to route.
    802       if (message->is_sync()) {
    803         IPC::Message* reply = IPC::SyncMessage::GenerateReply(&*message);
    804         reply->set_reply_error();
    805         Send(reply);
    806       }
    807     } else {
    808       // If the command buffer becomes unscheduled as a result of handling the
    809       // message but still has more commands to process, synthesize an IPC
    810       // message to flush that command buffer.
    811       if (stub) {
    812         if (stub->HasUnprocessedCommands()) {
    813           deferred_messages_.push_front(new GpuCommandBufferMsg_Rescheduled(
    814               stub->route_id()));
    815           message_processed = false;
    816         }
    817       }
    818     }
    819     if (message_processed)
    820       MessageProcessed();
    821 
    822     // We want the EchoACK following the SwapBuffers to be sent as close as
    823     // possible, avoiding scheduling other channels in the meantime.
    824     should_fast_track_ack = false;
    825     if (!deferred_messages_.empty()) {
    826       m = deferred_messages_.front();
    827       stub = stubs_.Lookup(m->routing_id());
    828       should_fast_track_ack =
    829           (m->type() == GpuCommandBufferMsg_Echo::ID) &&
    830           stub && stub->IsScheduled();
    831     }
    832   } while (should_fast_track_ack);
    833 
    834   if (!deferred_messages_.empty()) {
    835     OnScheduled();
    836   }
    837 }
    838 
    839 void GpuChannel::OnCreateOffscreenCommandBuffer(
    840     const gfx::Size& size,
    841     const GPUCreateCommandBufferConfig& init_params,
    842     int32* route_id) {
    843   TRACE_EVENT0("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer");
    844   GpuCommandBufferStub* share_group = stubs_.Lookup(init_params.share_group_id);
    845 
    846   *route_id = GenerateRouteID();
    847 
    848   scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
    849       this,
    850       share_group,
    851       gfx::GLSurfaceHandle(),
    852       mailbox_manager_.get(),
    853       image_manager_.get(),
    854       size,
    855       disallowed_features_,
    856       init_params.attribs,
    857       init_params.gpu_preference,
    858       false,
    859       *route_id,
    860       0,
    861       watchdog_,
    862       software_,
    863       init_params.active_url));
    864   if (preempted_flag_.get())
    865     stub->SetPreemptByFlag(preempted_flag_);
    866   router_.AddRoute(*route_id, stub.get());
    867   stubs_.AddWithID(stub.release(), *route_id);
    868   TRACE_EVENT1("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer",
    869                "route_id", route_id);
    870 }
    871 
    872 void GpuChannel::OnDestroyCommandBuffer(int32 route_id) {
    873   TRACE_EVENT1("gpu", "GpuChannel::OnDestroyCommandBuffer",
    874                "route_id", route_id);
    875 
    876   GpuCommandBufferStub* stub = stubs_.Lookup(route_id);
    877   if (!stub)
    878     return;
    879   bool need_reschedule = (stub && !stub->IsScheduled());
    880   router_.RemoveRoute(route_id);
    881   stubs_.Remove(route_id);
    882   // In case the renderer is currently blocked waiting for a sync reply from the
    883   // stub, we need to make sure to reschedule the GpuChannel here.
    884   if (need_reschedule) {
    885     // This stub won't get a chance to reschedule, so update the count now.
    886     StubSchedulingChanged(true);
    887   }
    888 }
    889 
    890 void GpuChannel::OnCreateVideoEncoder(int32* route_id) {
    891   TRACE_EVENT0("gpu", "GpuChannel::OnCreateVideoEncoder");
    892 
    893   *route_id = GenerateRouteID();
    894   GpuVideoEncodeAccelerator* encoder =
    895       new GpuVideoEncodeAccelerator(this, *route_id);
    896   router_.AddRoute(*route_id, encoder);
    897   video_encoders_.AddWithID(encoder, *route_id);
    898 }
    899 
    900 void GpuChannel::OnDestroyVideoEncoder(int32 route_id) {
    901   TRACE_EVENT1(
    902       "gpu", "GpuChannel::OnDestroyVideoEncoder", "route_id", route_id);
    903   GpuVideoEncodeAccelerator* encoder = video_encoders_.Lookup(route_id);
    904   if (!encoder)
    905     return;
    906   router_.RemoveRoute(route_id);
    907   video_encoders_.Remove(route_id);
    908 }
    909 
    910 void GpuChannel::OnDevToolsStartEventsRecording(int32* route_id) {
    911   devtools_gpu_agent_->StartEventsRecording(route_id);
    912 }
    913 
    914 void GpuChannel::OnDevToolsStopEventsRecording() {
    915   devtools_gpu_agent_->StopEventsRecording();
    916 }
    917 
    918 #if defined(OS_ANDROID)
    919 void GpuChannel::OnRegisterStreamTextureProxy(
    920     int32 stream_id, int32* route_id) {
    921   // Note that route_id is only used for notifications sent out from here.
    922   // StreamTextureManager owns all texture objects and for incoming messages
    923   // it finds the correct object based on stream_id.
    924   *route_id = GenerateRouteID();
    925   stream_texture_manager_->RegisterStreamTextureProxy(stream_id, *route_id);
    926 }
    927 
    928 void GpuChannel::OnEstablishStreamTexture(
    929     int32 stream_id, int32 primary_id, int32 secondary_id) {
    930   stream_texture_manager_->EstablishStreamTexture(
    931       stream_id, primary_id, secondary_id);
    932 }
    933 
    934 void GpuChannel::OnSetStreamTextureSize(
    935     int32 stream_id, const gfx::Size& size) {
    936   stream_texture_manager_->SetStreamTextureSize(stream_id, size);
    937 }
    938 #endif
    939 
    940 void GpuChannel::OnCollectRenderingStatsForSurface(
    941     int32 surface_id, GpuRenderingStats* stats) {
    942   for (StubMap::Iterator<GpuCommandBufferStub> it(&stubs_);
    943        !it.IsAtEnd(); it.Advance()) {
    944     int texture_upload_count =
    945         it.GetCurrentValue()->decoder()->GetTextureUploadCount();
    946     base::TimeDelta total_texture_upload_time =
    947         it.GetCurrentValue()->decoder()->GetTotalTextureUploadTime();
    948     base::TimeDelta total_processing_commands_time =
    949         it.GetCurrentValue()->decoder()->GetTotalProcessingCommandsTime();
    950 
    951     stats->global_texture_upload_count += texture_upload_count;
    952     stats->global_total_texture_upload_time += total_texture_upload_time;
    953     stats->global_total_processing_commands_time +=
    954         total_processing_commands_time;
    955     if (it.GetCurrentValue()->surface_id() == surface_id) {
    956       stats->texture_upload_count += texture_upload_count;
    957       stats->total_texture_upload_time += total_texture_upload_time;
    958       stats->total_processing_commands_time += total_processing_commands_time;
    959     }
    960   }
    961 
    962   GPUVideoMemoryUsageStats usage_stats;
    963   gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
    964       &usage_stats);
    965   stats->global_video_memory_bytes_allocated = usage_stats.bytes_allocated;
    966 }
    967 
    968 void GpuChannel::MessageProcessed() {
    969   messages_processed_++;
    970   if (preempting_flag_.get()) {
    971     io_message_loop_->PostTask(
    972         FROM_HERE,
    973         base::Bind(&GpuChannelMessageFilter::MessageProcessed,
    974                    filter_,
    975                    messages_processed_));
    976   }
    977 }
    978 
    979 void GpuChannel::CacheShader(const std::string& key,
    980                              const std::string& shader) {
    981   gpu_channel_manager_->Send(
    982       new GpuHostMsg_CacheShader(client_id_, key, shader));
    983 }
    984 
    985 void GpuChannel::AddFilter(IPC::ChannelProxy::MessageFilter* filter) {
    986   channel_->AddFilter(filter);
    987 }
    988 
    989 void GpuChannel::RemoveFilter(IPC::ChannelProxy::MessageFilter* filter) {
    990   channel_->RemoveFilter(filter);
    991 }
    992 
    993 }  // namespace content
    994