Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / content / common / gpu / gpu_channel.cc
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/stl_util.h"
19 #include "base/strings/string_util.h"
20 #include "base/timer/timer.h"
21 #include "content/common/gpu/devtools_gpu_agent.h"
22 #include "content/common/gpu/gpu_channel_manager.h"
23 #include "content/common/gpu/gpu_messages.h"
24 #include "content/common/gpu/sync_point_manager.h"
25 #include "content/public/common/content_switches.h"
26 #include "gpu/command_buffer/common/mailbox.h"
27 #include "gpu/command_buffer/service/gpu_scheduler.h"
28 #include "gpu/command_buffer/service/mailbox_manager_impl.h"
29 #include "ipc/ipc_channel.h"
30 #include "ipc/message_filter.h"
31 #include "ui/gl/gl_context.h"
32 #include "ui/gl/gl_surface.h"
33
34 #if defined(OS_POSIX)
35 #include "ipc/ipc_channel_posix.h"
36 #endif
37
38 namespace content {
39 namespace {
40
41 // Number of milliseconds between successive vsync. Many GL commands block
42 // on vsync, so thresholds for preemption should be multiples of this.
43 const int64 kVsyncIntervalMs = 17;
44
45 // Amount of time that we will wait for an IPC to be processed before
46 // preempting. After a preemption, we must wait this long before triggering
47 // another preemption.
48 const int64 kPreemptWaitTimeMs = 2 * kVsyncIntervalMs;
49
50 // Once we trigger a preemption, the maximum duration that we will wait
51 // before clearing the preemption.
52 const int64 kMaxPreemptTimeMs = kVsyncIntervalMs;
53
54 // Stop the preemption once the time for the longest pending IPC drops
55 // below this threshold.
56 const int64 kStopPreemptThresholdMs = kVsyncIntervalMs;
57
58 }  // anonymous namespace
59
60 // This filter does three things:
61 // - it counts and timestamps each message forwarded to the channel
62 //   so that we can preempt other channels if a message takes too long to
63 //   process. To guarantee fairness, we must wait a minimum amount of time
64 //   before preempting and we limit the amount of time that we can preempt in
65 //   one shot (see constants above).
66 // - it handles the GpuCommandBufferMsg_InsertSyncPoint message on the IO
67 //   thread, generating the sync point ID and responding immediately, and then
68 //   posting a task to insert the GpuCommandBufferMsg_RetireSyncPoint message
69 //   into the channel's queue.
70 // - it generates mailbox names for clients of the GPU process on the IO thread.
71 class GpuChannelMessageFilter : public IPC::MessageFilter {
72  public:
73   GpuChannelMessageFilter(base::WeakPtr<GpuChannel> gpu_channel,
74                           scoped_refptr<SyncPointManager> sync_point_manager,
75                           scoped_refptr<base::MessageLoopProxy> message_loop,
76                           bool future_sync_points)
77       : preemption_state_(IDLE),
78         gpu_channel_(gpu_channel),
79         sender_(NULL),
80         sync_point_manager_(sync_point_manager),
81         message_loop_(message_loop),
82         messages_forwarded_to_channel_(0),
83         a_stub_is_descheduled_(false),
84         future_sync_points_(future_sync_points) {}
85
86   void OnFilterAdded(IPC::Sender* sender) override {
87     DCHECK(!sender_);
88     sender_ = sender;
89   }
90
91   void OnFilterRemoved() override {
92     DCHECK(sender_);
93     sender_ = NULL;
94   }
95
96   bool OnMessageReceived(const IPC::Message& message) override {
97     DCHECK(sender_);
98
99     bool handled = false;
100     if ((message.type() == GpuCommandBufferMsg_RetireSyncPoint::ID) &&
101         !future_sync_points_) {
102       DLOG(ERROR) << "Untrusted client should not send "
103                      "GpuCommandBufferMsg_RetireSyncPoint message";
104       return true;
105     }
106
107     if (message.type() == GpuCommandBufferMsg_InsertSyncPoint::ID) {
108       Tuple1<bool> retire;
109       IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
110       if (!GpuCommandBufferMsg_InsertSyncPoint::ReadSendParam(&message,
111                                                               &retire)) {
112         reply->set_reply_error();
113         Send(reply);
114         return true;
115       }
116       if (!future_sync_points_ && !retire.a) {
117         LOG(ERROR) << "Untrusted contexts can't create future sync points";
118         reply->set_reply_error();
119         Send(reply);
120         return true;
121       }
122       uint32 sync_point = sync_point_manager_->GenerateSyncPoint();
123       GpuCommandBufferMsg_InsertSyncPoint::WriteReplyParams(reply, sync_point);
124       Send(reply);
125       message_loop_->PostTask(
126           FROM_HERE,
127           base::Bind(&GpuChannelMessageFilter::InsertSyncPointOnMainThread,
128                      gpu_channel_,
129                      sync_point_manager_,
130                      message.routing_id(),
131                      retire.a,
132                      sync_point));
133       handled = true;
134     }
135
136     // All other messages get processed by the GpuChannel.
137     messages_forwarded_to_channel_++;
138     if (preempting_flag_.get())
139       pending_messages_.push(PendingMessage(messages_forwarded_to_channel_));
140     UpdatePreemptionState();
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 sender_->Send(message);
166   }
167
168  protected:
169   ~GpuChannelMessageFilter() override {}
170
171  private:
172   enum PreemptionState {
173     // Either there's no other channel to preempt, there are no messages
174     // pending processing, or we just finished preempting and have to wait
175     // before preempting again.
176     IDLE,
177     // We are waiting kPreemptWaitTimeMs before checking if we should preempt.
178     WAITING,
179     // We can preempt whenever any IPC processing takes more than
180     // kPreemptWaitTimeMs.
181     CHECKING,
182     // We are currently preempting (i.e. no stub is descheduled).
183     PREEMPTING,
184     // We would like to preempt, but some stub is descheduled.
185     WOULD_PREEMPT_DESCHEDULED,
186   };
187
188   PreemptionState preemption_state_;
189
190   // Maximum amount of time that we can spend in PREEMPTING.
191   // It is reset when we transition to IDLE.
192   base::TimeDelta max_preemption_time_;
193
194   struct PendingMessage {
195     uint64 message_number;
196     base::TimeTicks time_received;
197
198     explicit PendingMessage(uint64 message_number)
199         : message_number(message_number),
200           time_received(base::TimeTicks::Now()) {
201     }
202   };
203
204   void UpdatePreemptionState() {
205     switch (preemption_state_) {
206       case IDLE:
207         if (preempting_flag_.get() && !pending_messages_.empty())
208           TransitionToWaiting();
209         break;
210       case WAITING:
211         // A timer will transition us to CHECKING.
212         DCHECK(timer_.IsRunning());
213         break;
214       case CHECKING:
215         if (!pending_messages_.empty()) {
216           base::TimeDelta time_elapsed =
217               base::TimeTicks::Now() - pending_messages_.front().time_received;
218           if (time_elapsed.InMilliseconds() < kPreemptWaitTimeMs) {
219             // Schedule another check for when the IPC may go long.
220             timer_.Start(
221                 FROM_HERE,
222                 base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs) -
223                     time_elapsed,
224                 this, &GpuChannelMessageFilter::UpdatePreemptionState);
225           } else {
226             if (a_stub_is_descheduled_)
227               TransitionToWouldPreemptDescheduled();
228             else
229               TransitionToPreempting();
230           }
231         }
232         break;
233       case PREEMPTING:
234         // A TransitionToIdle() timer should always be running in this state.
235         DCHECK(timer_.IsRunning());
236         if (a_stub_is_descheduled_)
237           TransitionToWouldPreemptDescheduled();
238         else
239           TransitionToIdleIfCaughtUp();
240         break;
241       case WOULD_PREEMPT_DESCHEDULED:
242         // A TransitionToIdle() timer should never be running in this state.
243         DCHECK(!timer_.IsRunning());
244         if (!a_stub_is_descheduled_)
245           TransitionToPreempting();
246         else
247           TransitionToIdleIfCaughtUp();
248         break;
249       default:
250         NOTREACHED();
251     }
252   }
253
254   void TransitionToIdleIfCaughtUp() {
255     DCHECK(preemption_state_ == PREEMPTING ||
256            preemption_state_ == WOULD_PREEMPT_DESCHEDULED);
257     if (pending_messages_.empty()) {
258       TransitionToIdle();
259     } else {
260       base::TimeDelta time_elapsed =
261           base::TimeTicks::Now() - pending_messages_.front().time_received;
262       if (time_elapsed.InMilliseconds() < kStopPreemptThresholdMs)
263         TransitionToIdle();
264     }
265   }
266
267   void TransitionToIdle() {
268     DCHECK(preemption_state_ == PREEMPTING ||
269            preemption_state_ == WOULD_PREEMPT_DESCHEDULED);
270     // Stop any outstanding timer set to force us from PREEMPTING to IDLE.
271     timer_.Stop();
272
273     preemption_state_ = IDLE;
274     preempting_flag_->Reset();
275     TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 0);
276
277     UpdatePreemptionState();
278   }
279
280   void TransitionToWaiting() {
281     DCHECK_EQ(preemption_state_, IDLE);
282     DCHECK(!timer_.IsRunning());
283
284     preemption_state_ = WAITING;
285     timer_.Start(
286         FROM_HERE,
287         base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs),
288         this, &GpuChannelMessageFilter::TransitionToChecking);
289   }
290
291   void TransitionToChecking() {
292     DCHECK_EQ(preemption_state_, WAITING);
293     DCHECK(!timer_.IsRunning());
294
295     preemption_state_ = CHECKING;
296     max_preemption_time_ = base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs);
297     UpdatePreemptionState();
298   }
299
300   void TransitionToPreempting() {
301     DCHECK(preemption_state_ == CHECKING ||
302            preemption_state_ == WOULD_PREEMPT_DESCHEDULED);
303     DCHECK(!a_stub_is_descheduled_);
304
305     // Stop any pending state update checks that we may have queued
306     // while CHECKING.
307     if (preemption_state_ == CHECKING)
308       timer_.Stop();
309
310     preemption_state_ = PREEMPTING;
311     preempting_flag_->Set();
312     TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 1);
313
314     timer_.Start(
315        FROM_HERE,
316        max_preemption_time_,
317        this, &GpuChannelMessageFilter::TransitionToIdle);
318
319     UpdatePreemptionState();
320   }
321
322   void TransitionToWouldPreemptDescheduled() {
323     DCHECK(preemption_state_ == CHECKING ||
324            preemption_state_ == PREEMPTING);
325     DCHECK(a_stub_is_descheduled_);
326
327     if (preemption_state_ == CHECKING) {
328       // Stop any pending state update checks that we may have queued
329       // while CHECKING.
330       timer_.Stop();
331     } else {
332       // Stop any TransitionToIdle() timers that we may have queued
333       // while PREEMPTING.
334       timer_.Stop();
335       max_preemption_time_ = timer_.desired_run_time() - base::TimeTicks::Now();
336       if (max_preemption_time_ < base::TimeDelta()) {
337         TransitionToIdle();
338         return;
339       }
340     }
341
342     preemption_state_ = WOULD_PREEMPT_DESCHEDULED;
343     preempting_flag_->Reset();
344     TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 0);
345
346     UpdatePreemptionState();
347   }
348
349   static void InsertSyncPointOnMainThread(
350       base::WeakPtr<GpuChannel> gpu_channel,
351       scoped_refptr<SyncPointManager> manager,
352       int32 routing_id,
353       bool retire,
354       uint32 sync_point) {
355     // This function must ensure that the sync point will be retired. Normally
356     // we'll find the stub based on the routing ID, and associate the sync point
357     // with it, but if that fails for any reason (channel or stub already
358     // deleted, invalid routing id), we need to retire the sync point
359     // immediately.
360     if (gpu_channel) {
361       GpuCommandBufferStub* stub = gpu_channel->LookupCommandBuffer(routing_id);
362       if (stub) {
363         stub->AddSyncPoint(sync_point);
364         if (retire) {
365           GpuCommandBufferMsg_RetireSyncPoint message(routing_id, sync_point);
366           gpu_channel->OnMessageReceived(message);
367         }
368         return;
369       } else {
370         gpu_channel->MessageProcessed();
371       }
372     }
373     manager->RetireSyncPoint(sync_point);
374   }
375
376   // NOTE: this weak pointer is never dereferenced on the IO thread, it's only
377   // passed through - therefore the WeakPtr assumptions are respected.
378   base::WeakPtr<GpuChannel> gpu_channel_;
379   IPC::Sender* sender_;
380   scoped_refptr<SyncPointManager> sync_point_manager_;
381   scoped_refptr<base::MessageLoopProxy> message_loop_;
382   scoped_refptr<gpu::PreemptionFlag> preempting_flag_;
383
384   std::queue<PendingMessage> pending_messages_;
385
386   // Count of the number of IPCs forwarded to the GpuChannel.
387   uint64 messages_forwarded_to_channel_;
388
389   base::OneShotTimer<GpuChannelMessageFilter> timer_;
390
391   bool a_stub_is_descheduled_;
392
393   // True if this channel can create future sync points.
394   bool future_sync_points_;
395 };
396
397 GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager,
398                        GpuWatchdog* watchdog,
399                        gfx::GLShareGroup* share_group,
400                        gpu::gles2::MailboxManager* mailbox,
401                        int client_id,
402                        bool software,
403                        bool allow_future_sync_points)
404     : gpu_channel_manager_(gpu_channel_manager),
405       messages_processed_(0),
406       client_id_(client_id),
407       share_group_(share_group ? share_group : new gfx::GLShareGroup),
408       mailbox_manager_(mailbox ? mailbox : new gpu::gles2::MailboxManagerImpl),
409       watchdog_(watchdog),
410       software_(software),
411       handle_messages_scheduled_(false),
412       currently_processing_message_(NULL),
413       num_stubs_descheduled_(0),
414       allow_future_sync_points_(allow_future_sync_points),
415       weak_factory_(this) {
416   DCHECK(gpu_channel_manager);
417   DCHECK(client_id);
418
419   channel_id_ = IPC::Channel::GenerateVerifiedChannelID("gpu");
420   const base::CommandLine* command_line =
421       base::CommandLine::ForCurrentProcess();
422   log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
423 }
424
425 GpuChannel::~GpuChannel() {
426   STLDeleteElements(&deferred_messages_);
427   if (preempting_flag_.get())
428     preempting_flag_->Reset();
429 }
430
431 void GpuChannel::Init(base::MessageLoopProxy* io_message_loop,
432                       base::WaitableEvent* shutdown_event) {
433   DCHECK(!channel_.get());
434
435   // Map renderer ID to a (single) channel to that process.
436   channel_ = IPC::SyncChannel::Create(channel_id_,
437                                       IPC::Channel::MODE_SERVER,
438                                       this,
439                                       io_message_loop,
440                                       false,
441                                       shutdown_event);
442
443   filter_ =
444       new GpuChannelMessageFilter(weak_factory_.GetWeakPtr(),
445                                   gpu_channel_manager_->sync_point_manager(),
446                                   base::MessageLoopProxy::current(),
447                                   allow_future_sync_points_);
448   io_message_loop_ = io_message_loop;
449   channel_->AddFilter(filter_.get());
450
451   devtools_gpu_agent_.reset(new DevToolsGpuAgent(this));
452 }
453
454 std::string GpuChannel::GetChannelName() {
455   return channel_id_;
456 }
457
458 #if defined(OS_POSIX)
459 base::ScopedFD GpuChannel::TakeRendererFileDescriptor() {
460   if (!channel_) {
461     NOTREACHED();
462     return base::ScopedFD();
463   }
464   return channel_->TakeClientFileDescriptor();
465 }
466 #endif  // defined(OS_POSIX)
467
468 bool GpuChannel::OnMessageReceived(const IPC::Message& message) {
469   if (log_messages_) {
470     DVLOG(1) << "received message @" << &message << " on channel @" << this
471              << " with type " << message.type();
472   }
473
474   if (message.type() == GpuCommandBufferMsg_WaitForTokenInRange::ID ||
475       message.type() == GpuCommandBufferMsg_WaitForGetOffsetInRange::ID) {
476     // Move Wait commands to the head of the queue, so the renderer
477     // doesn't have to wait any longer than necessary.
478     deferred_messages_.push_front(new IPC::Message(message));
479   } else {
480     deferred_messages_.push_back(new IPC::Message(message));
481   }
482
483   OnScheduled();
484
485   return true;
486 }
487
488 void GpuChannel::OnChannelError() {
489   gpu_channel_manager_->RemoveChannel(client_id_);
490 }
491
492 bool GpuChannel::Send(IPC::Message* message) {
493   // The GPU process must never send a synchronous IPC message to the renderer
494   // process. This could result in deadlock.
495   DCHECK(!message->is_sync());
496   if (log_messages_) {
497     DVLOG(1) << "sending message @" << message << " on channel @" << this
498              << " with type " << message->type();
499   }
500
501   if (!channel_) {
502     delete message;
503     return false;
504   }
505
506   return channel_->Send(message);
507 }
508
509 void GpuChannel::RequeueMessage() {
510   DCHECK(currently_processing_message_);
511   deferred_messages_.push_front(
512       new IPC::Message(*currently_processing_message_));
513   messages_processed_--;
514   currently_processing_message_ = NULL;
515 }
516
517 void GpuChannel::OnScheduled() {
518   if (handle_messages_scheduled_)
519     return;
520   // Post a task to handle any deferred messages. The deferred message queue is
521   // not emptied here, which ensures that OnMessageReceived will continue to
522   // defer newly received messages until the ones in the queue have all been
523   // handled by HandleMessage. HandleMessage is invoked as a
524   // task to prevent reentrancy.
525   base::MessageLoop::current()->PostTask(
526       FROM_HERE,
527       base::Bind(&GpuChannel::HandleMessage, weak_factory_.GetWeakPtr()));
528   handle_messages_scheduled_ = true;
529 }
530
531 void GpuChannel::StubSchedulingChanged(bool scheduled) {
532   bool a_stub_was_descheduled = num_stubs_descheduled_ > 0;
533   if (scheduled) {
534     num_stubs_descheduled_--;
535     OnScheduled();
536   } else {
537     num_stubs_descheduled_++;
538   }
539   DCHECK_LE(num_stubs_descheduled_, stubs_.size());
540   bool a_stub_is_descheduled = num_stubs_descheduled_ > 0;
541
542   if (a_stub_is_descheduled != a_stub_was_descheduled) {
543     if (preempting_flag_.get()) {
544       io_message_loop_->PostTask(
545           FROM_HERE,
546           base::Bind(&GpuChannelMessageFilter::UpdateStubSchedulingState,
547                      filter_,
548                      a_stub_is_descheduled));
549     }
550   }
551 }
552
553 CreateCommandBufferResult GpuChannel::CreateViewCommandBuffer(
554     const gfx::GLSurfaceHandle& window,
555     int32 surface_id,
556     const GPUCreateCommandBufferConfig& init_params,
557     int32 route_id) {
558   TRACE_EVENT1("gpu",
559                "GpuChannel::CreateViewCommandBuffer",
560                "surface_id",
561                surface_id);
562
563   GpuCommandBufferStub* share_group = stubs_.Lookup(init_params.share_group_id);
564
565   // Virtualize compositor contexts on OS X to prevent performance regressions
566   // when enabling FCM.
567   // http://crbug.com/180463
568   bool use_virtualized_gl_context = false;
569 #if defined(OS_MACOSX)
570   use_virtualized_gl_context = true;
571 #endif
572
573   scoped_ptr<GpuCommandBufferStub> stub(
574       new GpuCommandBufferStub(this,
575                                share_group,
576                                window,
577                                mailbox_manager_.get(),
578                                gfx::Size(),
579                                disallowed_features_,
580                                init_params.attribs,
581                                init_params.gpu_preference,
582                                use_virtualized_gl_context,
583                                route_id,
584                                surface_id,
585                                watchdog_,
586                                software_,
587                                init_params.active_url));
588   if (preempted_flag_.get())
589     stub->SetPreemptByFlag(preempted_flag_);
590   if (!router_.AddRoute(route_id, stub.get())) {
591     DLOG(ERROR) << "GpuChannel::CreateViewCommandBuffer(): "
592                    "failed to add route";
593     return CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST;
594   }
595   stubs_.AddWithID(stub.release(), route_id);
596   return CREATE_COMMAND_BUFFER_SUCCEEDED;
597 }
598
599 GpuCommandBufferStub* GpuChannel::LookupCommandBuffer(int32 route_id) {
600   return stubs_.Lookup(route_id);
601 }
602
603 void GpuChannel::LoseAllContexts() {
604   gpu_channel_manager_->LoseAllContexts();
605 }
606
607 void GpuChannel::MarkAllContextsLost() {
608   for (StubMap::Iterator<GpuCommandBufferStub> it(&stubs_);
609        !it.IsAtEnd(); it.Advance()) {
610     it.GetCurrentValue()->MarkContextLost();
611   }
612 }
613
614 bool GpuChannel::AddRoute(int32 route_id, IPC::Listener* listener) {
615   return router_.AddRoute(route_id, listener);
616 }
617
618 void GpuChannel::RemoveRoute(int32 route_id) {
619   router_.RemoveRoute(route_id);
620 }
621
622 gpu::PreemptionFlag* GpuChannel::GetPreemptionFlag() {
623   if (!preempting_flag_.get()) {
624     preempting_flag_ = new gpu::PreemptionFlag;
625     io_message_loop_->PostTask(
626         FROM_HERE, base::Bind(
627             &GpuChannelMessageFilter::SetPreemptingFlagAndSchedulingState,
628             filter_, preempting_flag_, num_stubs_descheduled_ > 0));
629   }
630   return preempting_flag_.get();
631 }
632
633 void GpuChannel::SetPreemptByFlag(
634     scoped_refptr<gpu::PreemptionFlag> preempted_flag) {
635   preempted_flag_ = preempted_flag;
636
637   for (StubMap::Iterator<GpuCommandBufferStub> it(&stubs_);
638        !it.IsAtEnd(); it.Advance()) {
639     it.GetCurrentValue()->SetPreemptByFlag(preempted_flag_);
640   }
641 }
642
643 void GpuChannel::OnDestroy() {
644   TRACE_EVENT0("gpu", "GpuChannel::OnDestroy");
645   gpu_channel_manager_->RemoveChannel(client_id_);
646 }
647
648 bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) {
649   bool handled = true;
650   IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg)
651     IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer,
652                         OnCreateOffscreenCommandBuffer)
653     IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer,
654                         OnDestroyCommandBuffer)
655     IPC_MESSAGE_HANDLER(GpuChannelMsg_DevToolsStartEventsRecording,
656                         OnDevToolsStartEventsRecording)
657     IPC_MESSAGE_HANDLER(GpuChannelMsg_DevToolsStopEventsRecording,
658                         OnDevToolsStopEventsRecording)
659     IPC_MESSAGE_UNHANDLED(handled = false)
660   IPC_END_MESSAGE_MAP()
661   DCHECK(handled) << msg.type();
662   return handled;
663 }
664
665 void GpuChannel::HandleMessage() {
666   handle_messages_scheduled_ = false;
667   if (deferred_messages_.empty())
668     return;
669
670   IPC::Message* m = NULL;
671   GpuCommandBufferStub* stub = NULL;
672
673   m = deferred_messages_.front();
674   stub = stubs_.Lookup(m->routing_id());
675   if (stub) {
676     if (!stub->IsScheduled())
677       return;
678     if (stub->IsPreempted()) {
679       OnScheduled();
680       return;
681     }
682   }
683
684   scoped_ptr<IPC::Message> message(m);
685   deferred_messages_.pop_front();
686   bool message_processed = true;
687
688   currently_processing_message_ = message.get();
689   bool result;
690   if (message->routing_id() == MSG_ROUTING_CONTROL)
691     result = OnControlMessageReceived(*message);
692   else
693     result = router_.RouteMessage(*message);
694   currently_processing_message_ = NULL;
695
696   if (!result) {
697     // Respond to sync messages even if router failed to route.
698     if (message->is_sync()) {
699       IPC::Message* reply = IPC::SyncMessage::GenerateReply(&*message);
700       reply->set_reply_error();
701       Send(reply);
702     }
703   } else {
704     // If the command buffer becomes unscheduled as a result of handling the
705     // message but still has more commands to process, synthesize an IPC
706     // message to flush that command buffer.
707     if (stub) {
708       if (stub->HasUnprocessedCommands()) {
709         deferred_messages_.push_front(new GpuCommandBufferMsg_Rescheduled(
710             stub->route_id()));
711         message_processed = false;
712       }
713     }
714   }
715   if (message_processed)
716     MessageProcessed();
717
718   if (!deferred_messages_.empty()) {
719     OnScheduled();
720   }
721 }
722
723 void GpuChannel::OnCreateOffscreenCommandBuffer(
724     const gfx::Size& size,
725     const GPUCreateCommandBufferConfig& init_params,
726     int32 route_id,
727     bool* succeeded) {
728   TRACE_EVENT0("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer");
729   GpuCommandBufferStub* share_group = stubs_.Lookup(init_params.share_group_id);
730
731   scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
732       this,
733       share_group,
734       gfx::GLSurfaceHandle(),
735       mailbox_manager_.get(),
736       size,
737       disallowed_features_,
738       init_params.attribs,
739       init_params.gpu_preference,
740       false,
741       route_id,
742       0,
743       watchdog_,
744       software_,
745       init_params.active_url));
746   if (preempted_flag_.get())
747     stub->SetPreemptByFlag(preempted_flag_);
748   if (!router_.AddRoute(route_id, stub.get())) {
749     DLOG(ERROR) << "GpuChannel::OnCreateOffscreenCommandBuffer(): "
750                    "failed to add route";
751     *succeeded = false;
752     return;
753   }
754   stubs_.AddWithID(stub.release(), route_id);
755   TRACE_EVENT1("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer",
756                "route_id", route_id);
757   *succeeded = true;
758 }
759
760 void GpuChannel::OnDestroyCommandBuffer(int32 route_id) {
761   TRACE_EVENT1("gpu", "GpuChannel::OnDestroyCommandBuffer",
762                "route_id", route_id);
763
764   GpuCommandBufferStub* stub = stubs_.Lookup(route_id);
765   if (!stub)
766     return;
767   bool need_reschedule = (stub && !stub->IsScheduled());
768   router_.RemoveRoute(route_id);
769   stubs_.Remove(route_id);
770   // In case the renderer is currently blocked waiting for a sync reply from the
771   // stub, we need to make sure to reschedule the GpuChannel here.
772   if (need_reschedule) {
773     // This stub won't get a chance to reschedule, so update the count now.
774     StubSchedulingChanged(true);
775   }
776 }
777
778 void GpuChannel::OnDevToolsStartEventsRecording(int32 route_id,
779                                                 bool* succeeded) {
780   *succeeded = devtools_gpu_agent_->StartEventsRecording(route_id);
781 }
782
783 void GpuChannel::OnDevToolsStopEventsRecording() {
784   devtools_gpu_agent_->StopEventsRecording();
785 }
786
787 void GpuChannel::MessageProcessed() {
788   messages_processed_++;
789   if (preempting_flag_.get()) {
790     io_message_loop_->PostTask(
791         FROM_HERE,
792         base::Bind(&GpuChannelMessageFilter::MessageProcessed,
793                    filter_,
794                    messages_processed_));
795   }
796 }
797
798 void GpuChannel::CacheShader(const std::string& key,
799                              const std::string& shader) {
800   gpu_channel_manager_->Send(
801       new GpuHostMsg_CacheShader(client_id_, key, shader));
802 }
803
804 void GpuChannel::AddFilter(IPC::MessageFilter* filter) {
805   channel_->AddFilter(filter);
806 }
807
808 void GpuChannel::RemoveFilter(IPC::MessageFilter* filter) {
809   channel_->RemoveFilter(filter);
810 }
811
812 uint64 GpuChannel::GetMemoryUsage() {
813   uint64 size = 0;
814   for (StubMap::Iterator<GpuCommandBufferStub> it(&stubs_);
815        !it.IsAtEnd(); it.Advance()) {
816     size += it.GetCurrentValue()->GetMemoryUsage();
817   }
818   return size;
819 }
820
821 }  // namespace content