1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/bind.h" 6 #include "base/bind_helpers.h" 7 #include "base/command_line.h" 8 #include "base/debug/trace_event.h" 9 #include "base/hash.h" 10 #include "base/memory/shared_memory.h" 11 #include "base/time/time.h" 12 #include "build/build_config.h" 13 #include "content/common/gpu/gpu_channel.h" 14 #include "content/common/gpu/gpu_channel_manager.h" 15 #include "content/common/gpu/gpu_command_buffer_stub.h" 16 #include "content/common/gpu/gpu_memory_manager.h" 17 #include "content/common/gpu/gpu_memory_tracking.h" 18 #include "content/common/gpu/gpu_messages.h" 19 #include "content/common/gpu/gpu_watchdog.h" 20 #include "content/common/gpu/image_transport_surface.h" 21 #include "content/common/gpu/media/gpu_video_decode_accelerator.h" 22 #include "content/common/gpu/sync_point_manager.h" 23 #include "content/public/common/content_client.h" 24 #include "content/public/common/content_switches.h" 25 #include "gpu/command_buffer/common/constants.h" 26 #include "gpu/command_buffer/common/gles2_cmd_utils.h" 27 #include "gpu/command_buffer/common/mailbox.h" 28 #include "gpu/command_buffer/service/gl_context_virtual.h" 29 #include "gpu/command_buffer/service/gl_state_restorer_impl.h" 30 #include "gpu/command_buffer/service/logger.h" 31 #include "gpu/command_buffer/service/memory_tracking.h" 32 #include "gpu/command_buffer/service/query_manager.h" 33 #include "ui/gl/gl_bindings.h" 34 #include "ui/gl/gl_switches.h" 35 36 #if defined(OS_WIN) 37 #include "content/public/common/sandbox_init.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 // The GpuCommandBufferMemoryTracker class provides a bridge between the 48 // ContextGroup's memory type managers and the GpuMemoryManager class. 49 class GpuCommandBufferMemoryTracker : public gpu::gles2::MemoryTracker { 50 public: 51 explicit GpuCommandBufferMemoryTracker(GpuChannel* channel) : 52 tracking_group_(channel->gpu_channel_manager()->gpu_memory_manager()-> 53 CreateTrackingGroup(channel->renderer_pid(), this)) { 54 } 55 56 virtual void TrackMemoryAllocatedChange( 57 size_t old_size, 58 size_t new_size, 59 gpu::gles2::MemoryTracker::Pool pool) OVERRIDE { 60 tracking_group_->TrackMemoryAllocatedChange( 61 old_size, new_size, pool); 62 } 63 64 virtual bool EnsureGPUMemoryAvailable(size_t size_needed) OVERRIDE { 65 return tracking_group_->EnsureGPUMemoryAvailable(size_needed); 66 }; 67 68 private: 69 virtual ~GpuCommandBufferMemoryTracker() { 70 } 71 scoped_ptr<GpuMemoryTrackingGroup> tracking_group_; 72 73 DISALLOW_COPY_AND_ASSIGN(GpuCommandBufferMemoryTracker); 74 }; 75 76 // FastSetActiveURL will shortcut the expensive call to SetActiveURL when the 77 // url_hash matches. 78 void FastSetActiveURL(const GURL& url, size_t url_hash) { 79 // Leave the previously set URL in the empty case -- empty URLs are given by 80 // WebKitPlatformSupportImpl::createOffscreenGraphicsContext3D. Hopefully the 81 // onscreen context URL was set previously and will show up even when a crash 82 // occurs during offscreen command processing. 83 if (url.is_empty()) 84 return; 85 static size_t g_last_url_hash = 0; 86 if (url_hash != g_last_url_hash) { 87 g_last_url_hash = url_hash; 88 GetContentClient()->SetActiveURL(url); 89 } 90 } 91 92 // The first time polling a fence, delay some extra time to allow other 93 // stubs to process some work, or else the timing of the fences could 94 // allow a pattern of alternating fast and slow frames to occur. 95 const int64 kHandleMoreWorkPeriodMs = 2; 96 const int64 kHandleMoreWorkPeriodBusyMs = 1; 97 98 // Prevents idle work from being starved. 99 const int64 kMaxTimeSinceIdleMs = 10; 100 101 } // namespace 102 103 GpuCommandBufferStub::GpuCommandBufferStub( 104 GpuChannel* channel, 105 GpuCommandBufferStub* share_group, 106 const gfx::GLSurfaceHandle& handle, 107 gpu::gles2::MailboxManager* mailbox_manager, 108 gpu::gles2::ImageManager* image_manager, 109 const gfx::Size& size, 110 const gpu::gles2::DisallowedFeatures& disallowed_features, 111 const std::string& allowed_extensions, 112 const std::vector<int32>& attribs, 113 gfx::GpuPreference gpu_preference, 114 bool use_virtualized_gl_context, 115 int32 route_id, 116 int32 surface_id, 117 GpuWatchdog* watchdog, 118 bool software, 119 const GURL& active_url) 120 : channel_(channel), 121 handle_(handle), 122 initial_size_(size), 123 disallowed_features_(disallowed_features), 124 allowed_extensions_(allowed_extensions), 125 requested_attribs_(attribs), 126 gpu_preference_(gpu_preference), 127 use_virtualized_gl_context_(use_virtualized_gl_context), 128 route_id_(route_id), 129 surface_id_(surface_id), 130 software_(software), 131 last_flush_count_(0), 132 last_memory_allocation_valid_(false), 133 watchdog_(watchdog), 134 sync_point_wait_count_(0), 135 delayed_work_scheduled_(false), 136 previous_messages_processed_(0), 137 active_url_(active_url), 138 total_gpu_memory_(0) { 139 active_url_hash_ = base::Hash(active_url.possibly_invalid_spec()); 140 FastSetActiveURL(active_url_, active_url_hash_); 141 if (share_group) { 142 context_group_ = share_group->context_group_; 143 } else { 144 gpu::StreamTextureManager* stream_texture_manager = NULL; 145 #if defined(OS_ANDROID) 146 stream_texture_manager = channel_->stream_texture_manager(); 147 #endif 148 context_group_ = new gpu::gles2::ContextGroup( 149 mailbox_manager, 150 image_manager, 151 new GpuCommandBufferMemoryTracker(channel), 152 stream_texture_manager, 153 true); 154 } 155 } 156 157 GpuCommandBufferStub::~GpuCommandBufferStub() { 158 Destroy(); 159 160 GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); 161 gpu_channel_manager->Send(new GpuHostMsg_DestroyCommandBuffer(surface_id())); 162 } 163 164 GpuMemoryManager* GpuCommandBufferStub::GetMemoryManager() { 165 return channel()->gpu_channel_manager()->gpu_memory_manager(); 166 } 167 168 bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) { 169 FastSetActiveURL(active_url_, active_url_hash_); 170 171 // Ensure the appropriate GL context is current before handling any IPC 172 // messages directed at the command buffer. This ensures that the message 173 // handler can assume that the context is current (not necessary for 174 // Echo, RetireSyncPoint, or WaitSyncPoint). 175 if (decoder_.get() && 176 message.type() != GpuCommandBufferMsg_Echo::ID && 177 message.type() != GpuCommandBufferMsg_GetStateFast::ID && 178 message.type() != GpuCommandBufferMsg_RetireSyncPoint::ID && 179 message.type() != GpuCommandBufferMsg_SetLatencyInfo::ID) { 180 if (!MakeCurrent()) 181 return false; 182 } 183 184 // Always use IPC_MESSAGE_HANDLER_DELAY_REPLY for synchronous message handlers 185 // here. This is so the reply can be delayed if the scheduler is unscheduled. 186 bool handled = true; 187 IPC_BEGIN_MESSAGE_MAP(GpuCommandBufferStub, message) 188 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_Initialize, 189 OnInitialize); 190 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_SetGetBuffer, 191 OnSetGetBuffer); 192 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ProduceFrontBuffer, 193 OnProduceFrontBuffer); 194 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Echo, OnEcho); 195 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_GetState, OnGetState); 196 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_GetStateFast, 197 OnGetStateFast); 198 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncFlush, OnAsyncFlush); 199 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SetLatencyInfo, OnSetLatencyInfo); 200 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Rescheduled, OnRescheduled); 201 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RegisterTransferBuffer, 202 OnRegisterTransferBuffer); 203 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyTransferBuffer, 204 OnDestroyTransferBuffer); 205 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_GetTransferBuffer, 206 OnGetTransferBuffer); 207 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuCommandBufferMsg_CreateVideoDecoder, 208 OnCreateVideoDecoder) 209 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SetSurfaceVisible, 210 OnSetSurfaceVisible) 211 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DiscardBackbuffer, 212 OnDiscardBackbuffer) 213 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_EnsureBackbuffer, 214 OnEnsureBackbuffer) 215 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RetireSyncPoint, 216 OnRetireSyncPoint) 217 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SignalSyncPoint, 218 OnSignalSyncPoint) 219 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SignalQuery, 220 OnSignalQuery) 221 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SendClientManagedMemoryStats, 222 OnReceivedClientManagedMemoryStats) 223 IPC_MESSAGE_HANDLER( 224 GpuCommandBufferMsg_SetClientHasMemoryAllocationChangedCallback, 225 OnSetClientHasMemoryAllocationChangedCallback) 226 IPC_MESSAGE_UNHANDLED(handled = false) 227 IPC_END_MESSAGE_MAP() 228 229 // Ensure that any delayed work that was created will be handled. 230 ScheduleDelayedWork(kHandleMoreWorkPeriodMs); 231 232 DCHECK(handled); 233 return handled; 234 } 235 236 bool GpuCommandBufferStub::Send(IPC::Message* message) { 237 return channel_->Send(message); 238 } 239 240 bool GpuCommandBufferStub::IsScheduled() { 241 return (!scheduler_.get() || scheduler_->IsScheduled()); 242 } 243 244 bool GpuCommandBufferStub::HasMoreWork() { 245 return scheduler_.get() && scheduler_->HasMoreWork(); 246 } 247 248 void GpuCommandBufferStub::PollWork() { 249 TRACE_EVENT0("gpu", "GpuCommandBufferStub::PollWork"); 250 delayed_work_scheduled_ = false; 251 FastSetActiveURL(active_url_, active_url_hash_); 252 if (decoder_.get() && !MakeCurrent()) 253 return; 254 255 if (scheduler_) { 256 bool fences_complete = scheduler_->PollUnscheduleFences(); 257 // Perform idle work if all fences are complete. 258 if (fences_complete) { 259 uint64 current_messages_processed = 260 channel()->gpu_channel_manager()->MessagesProcessed(); 261 // We're idle when no messages were processed or scheduled. 262 bool is_idle = 263 (previous_messages_processed_ == current_messages_processed) && 264 !channel()->gpu_channel_manager()->HandleMessagesScheduled(); 265 if (!is_idle && !last_idle_time_.is_null()) { 266 base::TimeDelta time_since_idle = base::TimeTicks::Now() - 267 last_idle_time_; 268 base::TimeDelta max_time_since_idle = 269 base::TimeDelta::FromMilliseconds(kMaxTimeSinceIdleMs); 270 271 // Force idle when it's been too long since last time we were idle. 272 if (time_since_idle > max_time_since_idle) 273 is_idle = true; 274 } 275 276 if (is_idle) { 277 last_idle_time_ = base::TimeTicks::Now(); 278 scheduler_->PerformIdleWork(); 279 } 280 } 281 } 282 ScheduleDelayedWork(kHandleMoreWorkPeriodBusyMs); 283 } 284 285 bool GpuCommandBufferStub::HasUnprocessedCommands() { 286 if (command_buffer_) { 287 gpu::CommandBuffer::State state = command_buffer_->GetLastState(); 288 return state.put_offset != state.get_offset && 289 !gpu::error::IsError(state.error); 290 } 291 return false; 292 } 293 294 void GpuCommandBufferStub::ScheduleDelayedWork(int64 delay) { 295 if (!HasMoreWork()) { 296 last_idle_time_ = base::TimeTicks(); 297 return; 298 } 299 300 if (delayed_work_scheduled_) 301 return; 302 delayed_work_scheduled_ = true; 303 304 // Idle when no messages are processed between now and when 305 // PollWork is called. 306 previous_messages_processed_ = 307 channel()->gpu_channel_manager()->MessagesProcessed(); 308 if (last_idle_time_.is_null()) 309 last_idle_time_ = base::TimeTicks::Now(); 310 311 // IsScheduled() returns true after passing all unschedule fences 312 // and this is when we can start performing idle work. Idle work 313 // is done synchronously so we can set delay to 0 and instead poll 314 // for more work at the rate idle work is performed. This also ensures 315 // that idle work is done as efficiently as possible without any 316 // unnecessary delays. 317 if (scheduler_.get() && 318 scheduler_->IsScheduled() && 319 scheduler_->HasMoreIdleWork()) { 320 delay = 0; 321 } 322 323 base::MessageLoop::current()->PostDelayedTask( 324 FROM_HERE, 325 base::Bind(&GpuCommandBufferStub::PollWork, AsWeakPtr()), 326 base::TimeDelta::FromMilliseconds(delay)); 327 } 328 329 void GpuCommandBufferStub::OnEcho(const IPC::Message& message) { 330 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnEcho"); 331 Send(new IPC::Message(message)); 332 } 333 334 bool GpuCommandBufferStub::MakeCurrent() { 335 if (decoder_->MakeCurrent()) 336 return true; 337 DLOG(ERROR) << "Context lost because MakeCurrent failed."; 338 command_buffer_->SetContextLostReason(decoder_->GetContextLostReason()); 339 command_buffer_->SetParseError(gpu::error::kLostContext); 340 CheckContextLost(); 341 return false; 342 } 343 344 void GpuCommandBufferStub::Destroy() { 345 if (handle_.is_null() && !active_url_.is_empty()) { 346 GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); 347 gpu_channel_manager->Send(new GpuHostMsg_DidDestroyOffscreenContext( 348 active_url_)); 349 } 350 351 memory_manager_client_state_.reset(); 352 353 while (!sync_points_.empty()) 354 OnRetireSyncPoint(sync_points_.front()); 355 356 if (decoder_) 357 decoder_->set_engine(NULL); 358 359 // The scheduler has raw references to the decoder and the command buffer so 360 // destroy it before those. 361 scheduler_.reset(); 362 363 bool have_context = false; 364 if (decoder_ && command_buffer_ && 365 command_buffer_->GetState().error != gpu::error::kLostContext) 366 have_context = decoder_->MakeCurrent(); 367 FOR_EACH_OBSERVER(DestructionObserver, 368 destruction_observers_, 369 OnWillDestroyStub()); 370 371 if (decoder_) { 372 decoder_->Destroy(have_context); 373 decoder_.reset(); 374 } 375 376 command_buffer_.reset(); 377 378 // Remove this after crbug.com/248395 is sorted out. 379 surface_ = NULL; 380 } 381 382 void GpuCommandBufferStub::OnInitializeFailed(IPC::Message* reply_message) { 383 Destroy(); 384 GpuCommandBufferMsg_Initialize::WriteReplyParams(reply_message, false); 385 Send(reply_message); 386 } 387 388 void GpuCommandBufferStub::OnInitialize( 389 base::SharedMemoryHandle shared_state_handle, 390 IPC::Message* reply_message) { 391 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnInitialize"); 392 DCHECK(!command_buffer_.get()); 393 394 scoped_ptr<base::SharedMemory> shared_state_shm( 395 new base::SharedMemory(shared_state_handle, false)); 396 397 command_buffer_.reset(new gpu::CommandBufferService( 398 context_group_->transfer_buffer_manager())); 399 400 if (!command_buffer_->Initialize()) { 401 DLOG(ERROR) << "CommandBufferService failed to initialize.\n"; 402 OnInitializeFailed(reply_message); 403 return; 404 } 405 406 decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group_.get())); 407 408 scheduler_.reset(new gpu::GpuScheduler(command_buffer_.get(), 409 decoder_.get(), 410 decoder_.get())); 411 if (preemption_flag_.get()) 412 scheduler_->SetPreemptByFlag(preemption_flag_); 413 414 decoder_->set_engine(scheduler_.get()); 415 416 if (!handle_.is_null()) { 417 #if defined(OS_MACOSX) || defined(UI_COMPOSITOR_IMAGE_TRANSPORT) 418 if (software_) { 419 DLOG(ERROR) << "No software support.\n"; 420 OnInitializeFailed(reply_message); 421 return; 422 } 423 #endif 424 425 surface_ = ImageTransportSurface::CreateSurface( 426 channel_->gpu_channel_manager(), 427 this, 428 handle_); 429 } else { 430 GpuChannelManager* manager = channel_->gpu_channel_manager(); 431 surface_ = manager->GetDefaultOffscreenSurface(); 432 } 433 434 if (!surface_.get()) { 435 DLOG(ERROR) << "Failed to create surface.\n"; 436 OnInitializeFailed(reply_message); 437 return; 438 } 439 440 scoped_refptr<gfx::GLContext> context; 441 if ((CommandLine::ForCurrentProcess()->HasSwitch( 442 switches::kEnableVirtualGLContexts) || use_virtualized_gl_context_) && 443 channel_->share_group()) { 444 context = channel_->share_group()->GetSharedContext(); 445 if (!context.get()) { 446 context = gfx::GLContext::CreateGLContext( 447 channel_->share_group(), 448 channel_->gpu_channel_manager()->GetDefaultOffscreenSurface(), 449 gpu_preference_); 450 channel_->share_group()->SetSharedContext(context.get()); 451 } 452 // This should be a non-virtual GL context. 453 DCHECK(context->GetHandle()); 454 context = new gpu::GLContextVirtual( 455 channel_->share_group(), context.get(), decoder_->AsWeakPtr()); 456 if (!context->Initialize(surface_.get(), gpu_preference_)) { 457 // TODO(sievers): The real context created above for the default 458 // offscreen surface might not be compatible with this surface. 459 // Need to adjust at least GLX to be able to create the initial context 460 // with a config that is compatible with onscreen and offscreen surfaces. 461 context = NULL; 462 463 DLOG(ERROR) << "Failed to initialize virtual GL context."; 464 OnInitializeFailed(reply_message); 465 return; 466 } 467 } 468 if (!context.get()) { 469 context = gfx::GLContext::CreateGLContext( 470 channel_->share_group(), surface_.get(), gpu_preference_); 471 } 472 if (!context.get()) { 473 DLOG(ERROR) << "Failed to create context.\n"; 474 OnInitializeFailed(reply_message); 475 return; 476 } 477 478 if (!context->MakeCurrent(surface_.get())) { 479 LOG(ERROR) << "Failed to make context current."; 480 OnInitializeFailed(reply_message); 481 return; 482 } 483 484 if (!context->GetGLStateRestorer()) { 485 context->SetGLStateRestorer( 486 new gpu::GLStateRestorerImpl(decoder_->AsWeakPtr())); 487 } 488 489 if (!context->GetTotalGpuMemory(&total_gpu_memory_)) 490 total_gpu_memory_ = 0; 491 492 if (!context_group_->has_program_cache()) { 493 context_group_->set_program_cache( 494 channel_->gpu_channel_manager()->program_cache()); 495 } 496 497 // Initialize the decoder with either the view or pbuffer GLContext. 498 if (!decoder_->Initialize(surface_, 499 context, 500 !surface_id(), 501 initial_size_, 502 disallowed_features_, 503 allowed_extensions_.c_str(), 504 requested_attribs_)) { 505 DLOG(ERROR) << "Failed to initialize decoder."; 506 OnInitializeFailed(reply_message); 507 return; 508 } 509 510 if (CommandLine::ForCurrentProcess()->HasSwitch( 511 switches::kEnableGPUServiceLogging)) { 512 decoder_->set_log_commands(true); 513 } 514 515 decoder_->GetLogger()->SetMsgCallback( 516 base::Bind(&GpuCommandBufferStub::SendConsoleMessage, 517 base::Unretained(this))); 518 decoder_->SetShaderCacheCallback( 519 base::Bind(&GpuCommandBufferStub::SendCachedShader, 520 base::Unretained(this))); 521 decoder_->SetWaitSyncPointCallback( 522 base::Bind(&GpuCommandBufferStub::OnWaitSyncPoint, 523 base::Unretained(this))); 524 525 command_buffer_->SetPutOffsetChangeCallback( 526 base::Bind(&GpuCommandBufferStub::PutChanged, base::Unretained(this))); 527 command_buffer_->SetGetBufferChangeCallback( 528 base::Bind(&gpu::GpuScheduler::SetGetBuffer, 529 base::Unretained(scheduler_.get()))); 530 command_buffer_->SetParseErrorCallback( 531 base::Bind(&GpuCommandBufferStub::OnParseError, base::Unretained(this))); 532 scheduler_->SetSchedulingChangedCallback( 533 base::Bind(&GpuChannel::StubSchedulingChanged, 534 base::Unretained(channel_))); 535 536 if (watchdog_) { 537 scheduler_->SetCommandProcessedCallback( 538 base::Bind(&GpuCommandBufferStub::OnCommandProcessed, 539 base::Unretained(this))); 540 } 541 542 if (!command_buffer_->SetSharedStateBuffer(shared_state_shm.Pass())) { 543 DLOG(ERROR) << "Failed to map shared stae buffer."; 544 OnInitializeFailed(reply_message); 545 return; 546 } 547 548 GpuCommandBufferMsg_Initialize::WriteReplyParams(reply_message, true); 549 Send(reply_message); 550 551 if (handle_.is_null() && !active_url_.is_empty()) { 552 GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); 553 gpu_channel_manager->Send(new GpuHostMsg_DidCreateOffscreenContext( 554 active_url_)); 555 } 556 } 557 558 void GpuCommandBufferStub::OnSetLatencyInfo( 559 const ui::LatencyInfo& latency_info) { 560 if (!latency_info_callback_.is_null()) 561 latency_info_callback_.Run(latency_info); 562 } 563 564 void GpuCommandBufferStub::SetLatencyInfoCallback( 565 const LatencyInfoCallback& callback) { 566 latency_info_callback_ = callback; 567 } 568 569 void GpuCommandBufferStub::OnSetGetBuffer(int32 shm_id, 570 IPC::Message* reply_message) { 571 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnSetGetBuffer"); 572 if (command_buffer_) 573 command_buffer_->SetGetBuffer(shm_id); 574 Send(reply_message); 575 } 576 577 void GpuCommandBufferStub::OnProduceFrontBuffer(const gpu::Mailbox& mailbox) { 578 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnProduceFrontBuffer"); 579 if (!decoder_) 580 LOG(ERROR) << "Can't produce front buffer before initialization."; 581 582 if (!decoder_->ProduceFrontBuffer(mailbox)) 583 LOG(ERROR) << "Failed to produce front buffer."; 584 } 585 586 void GpuCommandBufferStub::OnGetState(IPC::Message* reply_message) { 587 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnGetState"); 588 if (command_buffer_) { 589 gpu::CommandBuffer::State state = command_buffer_->GetState(); 590 CheckContextLost(); 591 GpuCommandBufferMsg_GetState::WriteReplyParams(reply_message, state); 592 } else { 593 DLOG(ERROR) << "no command_buffer."; 594 reply_message->set_reply_error(); 595 } 596 Send(reply_message); 597 } 598 599 void GpuCommandBufferStub::OnParseError() { 600 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnParseError"); 601 DCHECK(command_buffer_.get()); 602 gpu::CommandBuffer::State state = command_buffer_->GetState(); 603 IPC::Message* msg = new GpuCommandBufferMsg_Destroyed( 604 route_id_, state.context_lost_reason); 605 msg->set_unblock(true); 606 Send(msg); 607 608 // Tell the browser about this context loss as well, so it can 609 // determine whether client APIs like WebGL need to be immediately 610 // blocked from automatically running. 611 GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); 612 gpu_channel_manager->Send(new GpuHostMsg_DidLoseContext( 613 handle_.is_null(), state.context_lost_reason, active_url_)); 614 615 CheckContextLost(); 616 } 617 618 void GpuCommandBufferStub::OnGetStateFast(IPC::Message* reply_message) { 619 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnGetStateFast"); 620 DCHECK(command_buffer_.get()); 621 CheckContextLost(); 622 gpu::CommandBuffer::State state = command_buffer_->GetState(); 623 GpuCommandBufferMsg_GetStateFast::WriteReplyParams(reply_message, state); 624 Send(reply_message); 625 } 626 627 void GpuCommandBufferStub::OnAsyncFlush(int32 put_offset, 628 uint32 flush_count) { 629 TRACE_EVENT1("gpu", "GpuCommandBufferStub::OnAsyncFlush", 630 "put_offset", put_offset); 631 DCHECK(command_buffer_.get()); 632 if (flush_count - last_flush_count_ < 0x8000000U) { 633 last_flush_count_ = flush_count; 634 command_buffer_->Flush(put_offset); 635 } else { 636 // We received this message out-of-order. This should not happen but is here 637 // to catch regressions. Ignore the message. 638 NOTREACHED() << "Received a Flush message out-of-order"; 639 } 640 641 ReportState(); 642 } 643 644 void GpuCommandBufferStub::OnRescheduled() { 645 gpu::CommandBuffer::State pre_state = command_buffer_->GetLastState(); 646 command_buffer_->Flush(pre_state.put_offset); 647 gpu::CommandBuffer::State post_state = command_buffer_->GetLastState(); 648 649 if (pre_state.get_offset != post_state.get_offset) 650 ReportState(); 651 } 652 653 void GpuCommandBufferStub::OnRegisterTransferBuffer( 654 int32 id, 655 base::SharedMemoryHandle transfer_buffer, 656 uint32 size) { 657 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnRegisterTransferBuffer"); 658 base::SharedMemory shared_memory(transfer_buffer, false); 659 660 if (command_buffer_) 661 command_buffer_->RegisterTransferBuffer(id, &shared_memory, size); 662 } 663 664 void GpuCommandBufferStub::OnDestroyTransferBuffer(int32 id) { 665 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnDestroyTransferBuffer"); 666 667 if (command_buffer_) 668 command_buffer_->DestroyTransferBuffer(id); 669 } 670 671 void GpuCommandBufferStub::OnGetTransferBuffer( 672 int32 id, 673 IPC::Message* reply_message) { 674 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnGetTransferBuffer"); 675 if (command_buffer_) { 676 base::SharedMemoryHandle transfer_buffer = base::SharedMemoryHandle(); 677 uint32 size = 0; 678 679 gpu::Buffer buffer = command_buffer_->GetTransferBuffer(id); 680 if (buffer.shared_memory) { 681 #if defined(OS_WIN) 682 transfer_buffer = NULL; 683 BrokerDuplicateHandle(buffer.shared_memory->handle(), 684 channel_->renderer_pid(), &transfer_buffer, FILE_MAP_READ | 685 FILE_MAP_WRITE, 0); 686 DCHECK(transfer_buffer != NULL); 687 #else 688 buffer.shared_memory->ShareToProcess(channel_->renderer_pid(), 689 &transfer_buffer); 690 #endif 691 size = buffer.size; 692 } 693 694 GpuCommandBufferMsg_GetTransferBuffer::WriteReplyParams(reply_message, 695 transfer_buffer, 696 size); 697 } else { 698 reply_message->set_reply_error(); 699 } 700 Send(reply_message); 701 } 702 703 void GpuCommandBufferStub::OnCommandProcessed() { 704 if (watchdog_) 705 watchdog_->CheckArmed(); 706 } 707 708 void GpuCommandBufferStub::ReportState() { 709 if (!CheckContextLost()) 710 command_buffer_->UpdateState(); 711 } 712 713 void GpuCommandBufferStub::PutChanged() { 714 FastSetActiveURL(active_url_, active_url_hash_); 715 scheduler_->PutChanged(); 716 } 717 718 void GpuCommandBufferStub::OnCreateVideoDecoder( 719 media::VideoCodecProfile profile, 720 IPC::Message* reply_message) { 721 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnCreateVideoDecoder"); 722 int decoder_route_id = channel_->GenerateRouteID(); 723 GpuVideoDecodeAccelerator* decoder = 724 new GpuVideoDecodeAccelerator(decoder_route_id, this); 725 decoder->Initialize(profile, reply_message); 726 // decoder is registered as a DestructionObserver of this stub and will 727 // self-delete during destruction of this stub. 728 } 729 730 void GpuCommandBufferStub::OnSetSurfaceVisible(bool visible) { 731 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnSetSurfaceVisible"); 732 if (memory_manager_client_state_) 733 memory_manager_client_state_->SetVisible(visible); 734 } 735 736 void GpuCommandBufferStub::OnDiscardBackbuffer() { 737 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnDiscardBackbuffer"); 738 if (!surface_.get()) 739 return; 740 if (surface_->DeferDraws()) { 741 DCHECK(!IsScheduled()); 742 channel_->RequeueMessage(); 743 } else { 744 if (!surface_->SetBackbufferAllocation(false)) 745 channel_->DestroySoon(); 746 } 747 } 748 749 void GpuCommandBufferStub::OnEnsureBackbuffer() { 750 TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnEnsureBackbuffer"); 751 if (!surface_.get()) 752 return; 753 if (surface_->DeferDraws()) { 754 DCHECK(!IsScheduled()); 755 channel_->RequeueMessage(); 756 } else { 757 if (!surface_->SetBackbufferAllocation(true)) 758 channel_->DestroySoon(); 759 } 760 } 761 762 void GpuCommandBufferStub::AddSyncPoint(uint32 sync_point) { 763 sync_points_.push_back(sync_point); 764 } 765 766 void GpuCommandBufferStub::OnRetireSyncPoint(uint32 sync_point) { 767 DCHECK(!sync_points_.empty() && sync_points_.front() == sync_point); 768 sync_points_.pop_front(); 769 GpuChannelManager* manager = channel_->gpu_channel_manager(); 770 manager->sync_point_manager()->RetireSyncPoint(sync_point); 771 } 772 773 bool GpuCommandBufferStub::OnWaitSyncPoint(uint32 sync_point) { 774 if (sync_point_wait_count_ == 0) { 775 TRACE_EVENT_ASYNC_BEGIN1("gpu", "WaitSyncPoint", this, 776 "GpuCommandBufferStub", this); 777 } 778 scheduler_->SetScheduled(false); 779 ++sync_point_wait_count_; 780 GpuChannelManager* manager = channel_->gpu_channel_manager(); 781 manager->sync_point_manager()->AddSyncPointCallback( 782 sync_point, 783 base::Bind(&GpuCommandBufferStub::OnSyncPointRetired, 784 this->AsWeakPtr())); 785 return scheduler_->IsScheduled(); 786 } 787 788 void GpuCommandBufferStub::OnSyncPointRetired() { 789 --sync_point_wait_count_; 790 if (sync_point_wait_count_ == 0) { 791 TRACE_EVENT_ASYNC_END1("gpu", "WaitSyncPoint", this, 792 "GpuCommandBufferStub", this); 793 } 794 scheduler_->SetScheduled(true); 795 } 796 797 void GpuCommandBufferStub::OnSignalSyncPoint(uint32 sync_point, uint32 id) { 798 GpuChannelManager* manager = channel_->gpu_channel_manager(); 799 manager->sync_point_manager()->AddSyncPointCallback( 800 sync_point, 801 base::Bind(&GpuCommandBufferStub::OnSignalSyncPointAck, 802 this->AsWeakPtr(), 803 id)); 804 } 805 806 void GpuCommandBufferStub::OnSignalSyncPointAck(uint32 id) { 807 Send(new GpuCommandBufferMsg_SignalSyncPointAck(route_id_, id)); 808 } 809 810 void GpuCommandBufferStub::OnSignalQuery(uint32 query_id, uint32 id) { 811 if (decoder_) { 812 gpu::gles2::QueryManager* query_manager = decoder_->GetQueryManager(); 813 if (query_manager) { 814 gpu::gles2::QueryManager::Query* query = 815 query_manager->GetQuery(query_id); 816 if (query) { 817 query->AddCallback( 818 base::Bind(&GpuCommandBufferStub::OnSignalSyncPointAck, 819 this->AsWeakPtr(), 820 id)); 821 return; 822 } 823 } 824 } 825 // Something went wrong, run callback immediately. 826 OnSignalSyncPointAck(id); 827 } 828 829 830 void GpuCommandBufferStub::OnReceivedClientManagedMemoryStats( 831 const GpuManagedMemoryStats& stats) { 832 TRACE_EVENT0( 833 "gpu", 834 "GpuCommandBufferStub::OnReceivedClientManagedMemoryStats"); 835 if (memory_manager_client_state_) 836 memory_manager_client_state_->SetManagedMemoryStats(stats); 837 } 838 839 void GpuCommandBufferStub::OnSetClientHasMemoryAllocationChangedCallback( 840 bool has_callback) { 841 TRACE_EVENT0( 842 "gpu", 843 "GpuCommandBufferStub::OnSetClientHasMemoryAllocationChangedCallback"); 844 if (has_callback) { 845 if (!memory_manager_client_state_) { 846 memory_manager_client_state_.reset(GetMemoryManager()->CreateClientState( 847 this, surface_id_ != 0, true)); 848 } 849 } else { 850 memory_manager_client_state_.reset(); 851 } 852 } 853 854 void GpuCommandBufferStub::SendConsoleMessage( 855 int32 id, 856 const std::string& message) { 857 GPUCommandBufferConsoleMessage console_message; 858 console_message.id = id; 859 console_message.message = message; 860 IPC::Message* msg = new GpuCommandBufferMsg_ConsoleMsg( 861 route_id_, console_message); 862 msg->set_unblock(true); 863 Send(msg); 864 } 865 866 void GpuCommandBufferStub::SendCachedShader( 867 const std::string& key, const std::string& shader) { 868 channel_->CacheShader(key, shader); 869 } 870 871 void GpuCommandBufferStub::AddDestructionObserver( 872 DestructionObserver* observer) { 873 destruction_observers_.AddObserver(observer); 874 } 875 876 void GpuCommandBufferStub::RemoveDestructionObserver( 877 DestructionObserver* observer) { 878 destruction_observers_.RemoveObserver(observer); 879 } 880 881 void GpuCommandBufferStub::SetPreemptByFlag( 882 scoped_refptr<gpu::PreemptionFlag> flag) { 883 preemption_flag_ = flag; 884 if (scheduler_) 885 scheduler_->SetPreemptByFlag(preemption_flag_); 886 } 887 888 bool GpuCommandBufferStub::GetTotalGpuMemory(uint64* bytes) { 889 *bytes = total_gpu_memory_; 890 return !!total_gpu_memory_; 891 } 892 893 gfx::Size GpuCommandBufferStub::GetSurfaceSize() const { 894 if (!surface_.get()) 895 return gfx::Size(); 896 return surface_->GetSize(); 897 } 898 899 gpu::gles2::MemoryTracker* GpuCommandBufferStub::GetMemoryTracker() const { 900 return context_group_->memory_tracker(); 901 } 902 903 void GpuCommandBufferStub::SetMemoryAllocation( 904 const GpuMemoryAllocation& allocation) { 905 if (!last_memory_allocation_valid_ || 906 !allocation.renderer_allocation.Equals( 907 last_memory_allocation_.renderer_allocation)) { 908 Send(new GpuCommandBufferMsg_SetMemoryAllocation( 909 route_id_, allocation.renderer_allocation)); 910 } 911 912 if (!last_memory_allocation_valid_ || 913 !allocation.browser_allocation.Equals( 914 last_memory_allocation_.browser_allocation)) { 915 // This can be called outside of OnMessageReceived, so the context needs 916 // to be made current before calling methods on the surface. 917 if (surface_.get() && MakeCurrent()) 918 surface_->SetFrontbufferAllocation( 919 allocation.browser_allocation.suggest_have_frontbuffer); 920 } 921 922 last_memory_allocation_valid_ = true; 923 last_memory_allocation_ = allocation; 924 } 925 926 bool GpuCommandBufferStub::CheckContextLost() { 927 DCHECK(command_buffer_); 928 gpu::CommandBuffer::State state = command_buffer_->GetState(); 929 bool was_lost = state.error == gpu::error::kLostContext; 930 // Lose all other contexts if the reset was triggered by the robustness 931 // extension instead of being synthetic. 932 if (was_lost && decoder_ && decoder_->WasContextLostByRobustnessExtension() && 933 (gfx::GLContext::LosesAllContextsOnContextLost() || 934 use_virtualized_gl_context_)) 935 channel_->LoseAllContexts(); 936 return was_lost; 937 } 938 939 void GpuCommandBufferStub::MarkContextLost() { 940 if (!command_buffer_ || 941 command_buffer_->GetState().error == gpu::error::kLostContext) 942 return; 943 944 command_buffer_->SetContextLostReason(gpu::error::kUnknown); 945 if (decoder_) 946 decoder_->LoseContext(GL_UNKNOWN_CONTEXT_RESET_ARB); 947 command_buffer_->SetParseError(gpu::error::kLostContext); 948 } 949 950 } // namespace content 951