browser_gpu_channel_host_factory.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file. 4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/browser/gpu/browser_gpu_channel_host_factory.h" 6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/bind.h" 8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/debug/trace_event.h" 9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/browser/gpu/gpu_data_manager_impl.h" 11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/browser/gpu/gpu_process_host.h" 12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/browser/gpu/gpu_surface_tracker.h" 13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/common/child_process_host_impl.h" 14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/common/gpu/client/gpu_memory_buffer_impl_shm.h" 15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/common/gpu/gpu_messages.h" 16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/public/browser/gpu_data_manager.h" 18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/public/common/content_client.h" 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ipc/ipc_forwarding_message_filter.h" 20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace content { 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL; 24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)BrowserGpuChannelHostFactory::CreateRequest::CreateRequest() 26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : event(true, false), 27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gpu_host_id(0), 28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) route_id(MSG_ROUTING_NONE) { 29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 31effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochBrowserGpuChannelHostFactory::CreateRequest::~CreateRequest() { 32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest( 35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CauseForGpuLaunch cause, 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int gpu_client_id, 37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int gpu_host_id) 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : event_(false, false), 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) cause_for_gpu_launch_(cause), 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gpu_client_id_(gpu_client_id), 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gpu_host_id_(gpu_host_id), 42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) reused_gpu_process_(false), 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finished_(false), 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) main_loop_(base::MessageLoopProxy::current()) { 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_refptr<base::MessageLoopProxy> loop = 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) loop->PostTask( 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO, 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this)); 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() { 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() { 57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); 58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!host) { 59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) cause_for_gpu_launch_); 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!host) { 62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) LOG(ERROR) << "Failed to launch GPU process."; 63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FinishOnIO(); 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gpu_host_id_ = host->host_id(); 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) reused_gpu_process_ = false; 68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else { 69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (reused_gpu_process_) { 70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // We come here if we retried to establish the channel because of a 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // failure in ChannelEstablishedOnIO, but we ended up with the same 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // process ID, meaning the failure was not because of a channel error, 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // but another reason. So fail now. 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << "Failed to create channel."; 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FinishOnIO(); 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) reused_gpu_process_ = true; 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) host->EstablishGpuChannel( 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gpu_client_id_, 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) true, 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind( 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO, 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this)); 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO( 90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const IPC::ChannelHandle& channel_handle, 91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const gpu::GPUInfo& gpu_info) { 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (channel_handle.name.empty() && reused_gpu_process_) { 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // We failed after re-using the GPU process, but it may have died in the 94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // mean time. Retry to have a chance to create a fresh GPU process. 95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DVLOG(1) << "Failed to create channel on existing GPU process. Trying to " 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "restart GPU process."; 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EstablishOnIO(); 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else { 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) channel_handle_ = channel_handle; 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gpu_info_ = gpu_info; 101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FinishOnIO(); 102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() { 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event_.Signal(); 107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) main_loop_->PostTask( 108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FROM_HERE, 109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain, 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) this)); 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() { 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!finished_) { 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) BrowserGpuChannelHostFactory* factory = 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) BrowserGpuChannelHostFactory::instance(); 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) factory->GpuChannelEstablished(); 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) finished_ = true; 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BrowserGpuChannelHostFactory::EstablishRequest::Wait() { 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) { 125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // We're blocking the UI thread, which is generally undesirable. 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // In this case we need to wait for this before we can show any UI 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // /anyway/, so it won't cause additional jank. 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // TODO(piman): Make this asynchronous (http://crbug.com/125248). 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) TRACE_EVENT0("browser", 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "BrowserGpuChannelHostFactory::EstablishGpuChannelSync"); 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::ThreadRestrictions::ScopedAllowWait allow_wait; 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event_.Wait(); 133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FinishOnMain(); 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() { 138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(main_loop_->BelongsToCurrentThread()); 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) finished_ = true; 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool BrowserGpuChannelHostFactory::CanUseForTesting() { 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL); 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) { 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(!instance_); 148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) instance_ = new BrowserGpuChannelHostFactory(establish_gpu_channel); 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BrowserGpuChannelHostFactory::Terminate() { 152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(instance_); 153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delete instance_; 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) instance_ = NULL; 155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory( 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool establish_gpu_channel) 159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()), 160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) shutdown_event_(new base::WaitableEvent(true, false)), 161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gpu_host_id_(0) { 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (establish_gpu_channel) { 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pending_request_ = new EstablishRequest( 164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP, gpu_client_id_, gpu_host_id_); 165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() { 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(IsMainThread()); 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pending_request_) 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pending_request_->Cancel(); 172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (size_t n = 0; n < established_callbacks_.size(); n++) 173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) established_callbacks_[n].Run(); 174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) shutdown_event_->Signal(); 175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool BrowserGpuChannelHostFactory::IsMainThread() { 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return BrowserThread::CurrentlyOn(BrowserThread::UI); 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::MessageLoop* BrowserGpuChannelHostFactory::GetMainLoop() { 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI); 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_refptr<base::MessageLoopProxy> 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)BrowserGpuChannelHostFactory::GetIOLoopProxy() { 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<base::SharedMemory> 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) { 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<base::SharedMemory> shm(new base::SharedMemory()); 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!shm->CreateAnonymous(size)) 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return scoped_ptr<base::SharedMemory>(); 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return shm.Pass(); 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO( 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateRequest* request, 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int32 surface_id, 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const GPUCreateCommandBufferConfig& init_params) { 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!host) { 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request->event.Signal(); 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gfx::GLSurfaceHandle surface = 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id); 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) host->CreateViewCommandBuffer( 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) surface, 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) surface_id, 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gpu_client_id_, 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) init_params, 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request->route_id, 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO, 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request)); 219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static 222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO( 223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CreateRequest* request, bool succeeded) { 224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request->succeeded = succeeded; 225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request->event.Signal(); 226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool BrowserGpuChannelHostFactory::CreateViewCommandBuffer( 229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int32 surface_id, 230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const GPUCreateCommandBufferConfig& init_params, 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int32 route_id) { 232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CreateRequest request; 233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request.route_id = route_id; 234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind( 235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO, 236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Unretained(this), 237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) &request, 238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) surface_id, 239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) init_params)); 240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // We're blocking the UI thread, which is generally undesirable. 241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // In this case we need to wait for this before we can show any UI /anyway/, 242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // so it won't cause additional jank. 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // TODO(piman): Make this asynchronous (http://crbug.com/125248). 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) TRACE_EVENT0("browser", 245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) "BrowserGpuChannelHostFactory::CreateViewCommandBuffer"); 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::ThreadRestrictions::ScopedAllowWait allow_wait; 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request.event.Wait(); 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return request.succeeded; 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BrowserGpuChannelHostFactory::CreateImageOnIO( 252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::PluginWindowHandle window, 253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int32 image_id, 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const CreateImageCallback& callback) { 255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); 256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!host) { 257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ImageCreatedOnIO(callback, gfx::Size()); 258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) host->CreateImage( 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) window, 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gpu_client_id_, 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) image_id, 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&BrowserGpuChannelHostFactory::ImageCreatedOnIO, callback)); 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BrowserGpuChannelHostFactory::ImageCreatedOnIO( 2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const CreateImageCallback& callback, const gfx::Size size) { 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BrowserThread::PostTask( 2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BrowserThread::UI, 2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&BrowserGpuChannelHostFactory::OnImageCreated, 2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback, size)); 2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static 2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BrowserGpuChannelHostFactory::OnImageCreated( 2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const CreateImageCallback& callback, const gfx::Size size) { 2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(size); 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BrowserGpuChannelHostFactory::CreateImage( 2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gfx::PluginWindowHandle window, 2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int32 image_id, 2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const CreateImageCallback& callback) { 2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind( 2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &BrowserGpuChannelHostFactory::CreateImageOnIO, 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(this), 2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) window, 2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) image_id, 2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback)); 2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BrowserGpuChannelHostFactory::DeleteImageOnIO( 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int32 image_id, int32 sync_point) { 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); 3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!host) { 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) host->DeleteImage(gpu_client_id_, image_id, sync_point); 3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BrowserGpuChannelHostFactory::DeleteImage( 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int32 image_id, int32 sync_point) { 3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind( 3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &BrowserGpuChannelHostFactory::DeleteImageOnIO, 3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(this), 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) image_id, 3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sync_point)); 3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync( 3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CauseForGpuLaunch cause_for_gpu_launch) { 3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EstablishGpuChannel(cause_for_gpu_launch, base::Closure()); 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pending_request_) 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pending_request_->Wait(); 3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return gpu_channel_.get(); 3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BrowserGpuChannelHostFactory::EstablishGpuChannel( 3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CauseForGpuLaunch cause_for_gpu_launch, 3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Closure& callback) { 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (gpu_channel_.get() && gpu_channel_->IsLost()) { 3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(!pending_request_); 3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Recreate the channel if it has been lost. 3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gpu_channel_ = NULL; 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 336 if (!gpu_channel_ && !pending_request_) { 337 // We should only get here if the context was lost. 338 pending_request_ = new EstablishRequest( 339 cause_for_gpu_launch, gpu_client_id_, gpu_host_id_); 340 } 341 342 if (!callback.is_null()) { 343 if (gpu_channel_) 344 callback.Run(); 345 else 346 established_callbacks_.push_back(callback); 347 } 348} 349 350GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() { 351 if (gpu_channel_ && !gpu_channel_->IsLost()) 352 return gpu_channel_; 353 354 return NULL; 355} 356 357void BrowserGpuChannelHostFactory::GpuChannelEstablished() { 358 DCHECK(IsMainThread()); 359 DCHECK(pending_request_); 360 if (pending_request_->channel_handle().name.empty()) 361 return; 362 363 GetContentClient()->SetGpuInfo(pending_request_->gpu_info()); 364 gpu_channel_ = GpuChannelHost::Create(this, 365 pending_request_->gpu_info(), 366 pending_request_->channel_handle(), 367 shutdown_event_.get()); 368 gpu_host_id_ = pending_request_->gpu_host_id(); 369 pending_request_ = NULL; 370 371 for (size_t n = 0; n < established_callbacks_.size(); n++) 372 established_callbacks_[n].Run(); 373 374 established_callbacks_.clear(); 375} 376 377scoped_ptr<gfx::GpuMemoryBuffer> 378 BrowserGpuChannelHostFactory::AllocateGpuMemoryBuffer( 379 size_t width, 380 size_t height, 381 unsigned internalformat) { 382 if (!GpuMemoryBufferImpl::IsFormatValid(internalformat)) 383 return scoped_ptr<gfx::GpuMemoryBuffer>(); 384 385 size_t size = width * height * 386 GpuMemoryBufferImpl::BytesPerPixel(internalformat); 387 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory()); 388 if (!shm->CreateAnonymous(size)) 389 return scoped_ptr<gfx::GpuMemoryBuffer>(); 390 391 scoped_ptr<GpuMemoryBufferImplShm> buffer( 392 new GpuMemoryBufferImplShm(gfx::Size(width, height), internalformat)); 393 if (!buffer->InitializeFromSharedMemory(shm.Pass())) 394 return scoped_ptr<gfx::GpuMemoryBuffer>(); 395 396 return buffer.PassAs<gfx::GpuMemoryBuffer>(); 397} 398 399// static 400void BrowserGpuChannelHostFactory::AddFilterOnIO( 401 int host_id, 402 scoped_refptr<IPC::ChannelProxy::MessageFilter> filter) { 403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 404 405 GpuProcessHost* host = GpuProcessHost::FromID(host_id); 406 if (host) 407 host->AddFilter(filter.get()); 408} 409 410void BrowserGpuChannelHostFactory::SetHandlerForControlMessages( 411 const uint32* message_ids, 412 size_t num_messages, 413 const base::Callback<void(const IPC::Message&)>& handler, 414 base::TaskRunner* target_task_runner) { 415 DCHECK(gpu_host_id_) 416 << "Do not call" 417 << " BrowserGpuChannelHostFactory::SetHandlerForControlMessages()" 418 << " until the GpuProcessHost has been set up."; 419 420 scoped_refptr<IPC::ForwardingMessageFilter> filter = 421 new IPC::ForwardingMessageFilter(message_ids, 422 num_messages, 423 target_task_runner); 424 filter->AddRoute(MSG_ROUTING_CONTROL, handler); 425 426 GetIOLoopProxy()->PostTask( 427 FROM_HERE, 428 base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO, 429 gpu_host_id_, 430 filter)); 431} 432 433} // namespace content 434