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