| OLD | NEW |
| (Empty) |
| 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 "content/renderer/gpu/gpu_channel_host.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/message_loop.h" | |
| 9 #include "base/message_loop_proxy.h" | |
| 10 #include "content/common/child_thread.h" | |
| 11 #include "content/common/gpu/gpu_messages.h" | |
| 12 #include "content/renderer/gpu/command_buffer_proxy.h" | |
| 13 #include "googleurl/src/gurl.h" | |
| 14 #include "ipc/ipc_sync_message_filter.h" | |
| 15 | |
| 16 GpuChannelHostFactory* GpuChannelHostFactory::instance_ = NULL; | |
| 17 | |
| 18 GpuChannelHostFactory::~GpuChannelHostFactory() { | |
| 19 DCHECK(!instance_); | |
| 20 } | |
| 21 | |
| 22 using base::AutoLock; | |
| 23 using base::MessageLoopProxy; | |
| 24 | |
| 25 GpuListenerInfo::GpuListenerInfo() { | |
| 26 } | |
| 27 | |
| 28 GpuListenerInfo::~GpuListenerInfo() { | |
| 29 } | |
| 30 | |
| 31 GpuChannelHost::MessageFilter::MessageFilter(GpuChannelHost* parent) | |
| 32 : parent_(parent) { | |
| 33 } | |
| 34 | |
| 35 GpuChannelHost::MessageFilter::~MessageFilter() { | |
| 36 | |
| 37 } | |
| 38 | |
| 39 void GpuChannelHost::MessageFilter::AddRoute( | |
| 40 int route_id, | |
| 41 base::WeakPtr<IPC::Channel::Listener> listener, | |
| 42 scoped_refptr<MessageLoopProxy> loop) { | |
| 43 DCHECK(parent_->factory_->IsIOThread()); | |
| 44 DCHECK(listeners_.find(route_id) == listeners_.end()); | |
| 45 GpuListenerInfo info; | |
| 46 info.listener = listener; | |
| 47 info.loop = loop; | |
| 48 listeners_[route_id] = info; | |
| 49 } | |
| 50 | |
| 51 void GpuChannelHost::MessageFilter::RemoveRoute(int route_id) { | |
| 52 DCHECK(parent_->factory_->IsIOThread()); | |
| 53 ListenerMap::iterator it = listeners_.find(route_id); | |
| 54 if (it != listeners_.end()) | |
| 55 listeners_.erase(it); | |
| 56 } | |
| 57 | |
| 58 bool GpuChannelHost::MessageFilter::OnMessageReceived( | |
| 59 const IPC::Message& message) { | |
| 60 DCHECK(parent_->factory_->IsIOThread()); | |
| 61 // Never handle sync message replies or we will deadlock here. | |
| 62 if (message.is_reply()) | |
| 63 return false; | |
| 64 | |
| 65 DCHECK(message.routing_id() != MSG_ROUTING_CONTROL); | |
| 66 | |
| 67 ListenerMap::iterator it = listeners_.find(message.routing_id()); | |
| 68 | |
| 69 if (it != listeners_.end()) { | |
| 70 const GpuListenerInfo& info = it->second; | |
| 71 info.loop->PostTask( | |
| 72 FROM_HERE, | |
| 73 base::Bind( | |
| 74 base::IgnoreResult(&IPC::Channel::Listener::OnMessageReceived), | |
| 75 info.listener, | |
| 76 message)); | |
| 77 } | |
| 78 | |
| 79 return true; | |
| 80 } | |
| 81 | |
| 82 void GpuChannelHost::MessageFilter::OnChannelError() { | |
| 83 DCHECK(parent_->factory_->IsIOThread()); | |
| 84 // Inform all the proxies that an error has occurred. This will be reported | |
| 85 // via OpenGL as a lost context. | |
| 86 for (ListenerMap::iterator it = listeners_.begin(); | |
| 87 it != listeners_.end(); | |
| 88 it++) { | |
| 89 const GpuListenerInfo& info = it->second; | |
| 90 info.loop->PostTask( | |
| 91 FROM_HERE, | |
| 92 base::Bind(&IPC::Channel::Listener::OnChannelError, info.listener)); | |
| 93 } | |
| 94 | |
| 95 listeners_.clear(); | |
| 96 | |
| 97 MessageLoop* main_loop = parent_->factory_->GetMainLoop(); | |
| 98 main_loop->PostTask(FROM_HERE, | |
| 99 base::Bind(&GpuChannelHost::OnChannelError, parent_)); | |
| 100 } | |
| 101 | |
| 102 GpuChannelHost::GpuChannelHost(GpuChannelHostFactory* factory) | |
| 103 : factory_(factory), | |
| 104 state_(kUnconnected) { | |
| 105 } | |
| 106 | |
| 107 GpuChannelHost::~GpuChannelHost() { | |
| 108 } | |
| 109 | |
| 110 void GpuChannelHost::Connect( | |
| 111 const IPC::ChannelHandle& channel_handle, | |
| 112 base::ProcessHandle renderer_process_for_gpu) { | |
| 113 DCHECK(factory_->IsMainThread()); | |
| 114 // Open a channel to the GPU process. We pass NULL as the main listener here | |
| 115 // since we need to filter everything to route it to the right thread. | |
| 116 channel_.reset(new IPC::SyncChannel( | |
| 117 channel_handle, IPC::Channel::MODE_CLIENT, NULL, | |
| 118 factory_->GetIOLoopProxy(), true, | |
| 119 factory_->GetShutDownEvent())); | |
| 120 | |
| 121 sync_filter_ = new IPC::SyncMessageFilter( | |
| 122 factory_->GetShutDownEvent()); | |
| 123 | |
| 124 channel_->AddFilter(sync_filter_.get()); | |
| 125 | |
| 126 channel_filter_ = new MessageFilter(this); | |
| 127 | |
| 128 // Install the filter last, because we intercept all leftover | |
| 129 // messages. | |
| 130 channel_->AddFilter(channel_filter_.get()); | |
| 131 | |
| 132 // It is safe to send IPC messages before the channel completes the connection | |
| 133 // and receives the hello message from the GPU process. The messages get | |
| 134 // cached. | |
| 135 state_ = kConnected; | |
| 136 | |
| 137 // Notify the GPU process of our process handle. This gives it the ability | |
| 138 // to map renderer handles into the GPU process. | |
| 139 Send(new GpuChannelMsg_Initialize(renderer_process_for_gpu)); | |
| 140 } | |
| 141 | |
| 142 void GpuChannelHost::set_gpu_info(const content::GPUInfo& gpu_info) { | |
| 143 gpu_info_ = gpu_info; | |
| 144 } | |
| 145 | |
| 146 const content::GPUInfo& GpuChannelHost::gpu_info() const { | |
| 147 return gpu_info_; | |
| 148 } | |
| 149 | |
| 150 void GpuChannelHost::SetStateLost() { | |
| 151 state_ = kLost; | |
| 152 } | |
| 153 | |
| 154 void GpuChannelHost::OnChannelError() { | |
| 155 state_ = kLost; | |
| 156 | |
| 157 // Channel is invalid and will be reinitialized if this host is requested | |
| 158 // again. | |
| 159 channel_.reset(); | |
| 160 } | |
| 161 | |
| 162 bool GpuChannelHost::Send(IPC::Message* message) { | |
| 163 // The GPU process never sends synchronous IPCs so clear the unblock flag to | |
| 164 // preserve order. | |
| 165 message->set_unblock(false); | |
| 166 | |
| 167 // Currently we need to choose between two different mechanisms for sending. | |
| 168 // On the main thread we use the regular channel Send() method, on another | |
| 169 // thread we use SyncMessageFilter. We also have to be careful interpreting | |
| 170 // IsMainThread() since it might return false during shutdown, | |
| 171 // impl we are actually calling from the main thread (discard message then). | |
| 172 // | |
| 173 // TODO: Can we just always use sync_filter_ since we setup the channel | |
| 174 // without a main listener? | |
| 175 if (factory_->IsMainThread()) { | |
| 176 if (channel_.get()) | |
| 177 return channel_->Send(message); | |
| 178 } else if (MessageLoop::current()) { | |
| 179 return sync_filter_->Send(message); | |
| 180 } | |
| 181 | |
| 182 // Callee takes ownership of message, regardless of whether Send is | |
| 183 // successful. See IPC::Message::Sender. | |
| 184 delete message; | |
| 185 return false; | |
| 186 } | |
| 187 | |
| 188 CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer( | |
| 189 int32 surface_id, | |
| 190 CommandBufferProxy* share_group, | |
| 191 const std::string& allowed_extensions, | |
| 192 const std::vector<int32>& attribs, | |
| 193 const GURL& active_url, | |
| 194 gfx::GpuPreference gpu_preference) { | |
| 195 DCHECK(factory_->IsMainThread()); | |
| 196 #if defined(ENABLE_GPU) | |
| 197 AutoLock lock(context_lock_); | |
| 198 // An error occurred. Need to get the host again to reinitialize it. | |
| 199 if (!channel_.get()) | |
| 200 return NULL; | |
| 201 | |
| 202 GPUCreateCommandBufferConfig init_params; | |
| 203 init_params.share_group_id = | |
| 204 share_group ? share_group->route_id() : MSG_ROUTING_NONE; | |
| 205 init_params.allowed_extensions = allowed_extensions; | |
| 206 init_params.attribs = attribs; | |
| 207 init_params.active_url = active_url; | |
| 208 init_params.gpu_preference = gpu_preference; | |
| 209 int32 route_id = factory_->CreateViewCommandBuffer(surface_id, init_params); | |
| 210 if (route_id == MSG_ROUTING_NONE) | |
| 211 return NULL; | |
| 212 | |
| 213 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id); | |
| 214 AddRoute(route_id, command_buffer->AsWeakPtr()); | |
| 215 proxies_[route_id] = command_buffer; | |
| 216 return command_buffer; | |
| 217 #else | |
| 218 return NULL; | |
| 219 #endif | |
| 220 } | |
| 221 | |
| 222 GpuVideoDecodeAcceleratorHost* GpuChannelHost::CreateVideoDecoder( | |
| 223 int command_buffer_route_id, | |
| 224 media::VideoDecodeAccelerator::Profile profile, | |
| 225 media::VideoDecodeAccelerator::Client* client) { | |
| 226 AutoLock lock(context_lock_); | |
| 227 ProxyMap::iterator it = proxies_.find(command_buffer_route_id); | |
| 228 DCHECK(it != proxies_.end()); | |
| 229 CommandBufferProxy* proxy = it->second; | |
| 230 return proxy->CreateVideoDecoder(profile, client); | |
| 231 } | |
| 232 | |
| 233 CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer( | |
| 234 const gfx::Size& size, | |
| 235 CommandBufferProxy* share_group, | |
| 236 const std::string& allowed_extensions, | |
| 237 const std::vector<int32>& attribs, | |
| 238 const GURL& active_url, | |
| 239 gfx::GpuPreference gpu_preference) { | |
| 240 #if defined(ENABLE_GPU) | |
| 241 AutoLock lock(context_lock_); | |
| 242 // An error occurred. Need to get the host again to reinitialize it. | |
| 243 if (!channel_.get()) | |
| 244 return NULL; | |
| 245 | |
| 246 GPUCreateCommandBufferConfig init_params; | |
| 247 init_params.share_group_id = | |
| 248 share_group ? share_group->route_id() : MSG_ROUTING_NONE; | |
| 249 init_params.allowed_extensions = allowed_extensions; | |
| 250 init_params.attribs = attribs; | |
| 251 init_params.active_url = active_url; | |
| 252 init_params.gpu_preference = gpu_preference; | |
| 253 int32 route_id; | |
| 254 if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size, | |
| 255 init_params, | |
| 256 &route_id))) { | |
| 257 return NULL; | |
| 258 } | |
| 259 | |
| 260 if (route_id == MSG_ROUTING_NONE) | |
| 261 return NULL; | |
| 262 | |
| 263 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id); | |
| 264 AddRoute(route_id, command_buffer->AsWeakPtr()); | |
| 265 proxies_[route_id] = command_buffer; | |
| 266 return command_buffer; | |
| 267 #else | |
| 268 return NULL; | |
| 269 #endif | |
| 270 } | |
| 271 | |
| 272 void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) { | |
| 273 #if defined(ENABLE_GPU) | |
| 274 AutoLock lock(context_lock_); | |
| 275 Send(new GpuChannelMsg_DestroyCommandBuffer(command_buffer->route_id())); | |
| 276 | |
| 277 // Check the proxy has not already been removed after a channel error. | |
| 278 int route_id = command_buffer->route_id(); | |
| 279 if (proxies_.find(command_buffer->route_id()) != proxies_.end()) | |
| 280 proxies_.erase(route_id); | |
| 281 RemoveRoute(route_id); | |
| 282 delete command_buffer; | |
| 283 #endif | |
| 284 } | |
| 285 | |
| 286 void GpuChannelHost::AddRoute( | |
| 287 int route_id, base::WeakPtr<IPC::Channel::Listener> listener) { | |
| 288 DCHECK(MessageLoopProxy::current()); | |
| 289 | |
| 290 MessageLoopProxy* io_loop = factory_->GetIOLoopProxy(); | |
| 291 io_loop->PostTask(FROM_HERE, | |
| 292 base::Bind(&GpuChannelHost::MessageFilter::AddRoute, | |
| 293 channel_filter_.get(), route_id, listener, | |
| 294 MessageLoopProxy::current())); | |
| 295 } | |
| 296 | |
| 297 void GpuChannelHost::RemoveRoute(int route_id) { | |
| 298 MessageLoopProxy* io_loop = factory_->GetIOLoopProxy(); | |
| 299 io_loop->PostTask(FROM_HERE, | |
| 300 base::Bind(&GpuChannelHost::MessageFilter::RemoveRoute, | |
| 301 channel_filter_.get(), route_id)); | |
| 302 } | |
| 303 | |
| 304 bool GpuChannelHost::WillGpuSwitchOccur( | |
| 305 bool is_creating_context, gfx::GpuPreference gpu_preference) { | |
| 306 bool result = false; | |
| 307 if (!Send(new GpuChannelMsg_WillGpuSwitchOccur(is_creating_context, | |
| 308 gpu_preference, | |
| 309 &result))) { | |
| 310 return false; | |
| 311 } | |
| 312 return result; | |
| 313 } | |
| 314 | |
| 315 void GpuChannelHost::ForciblyCloseChannel() { | |
| 316 Send(new GpuChannelMsg_CloseChannel()); | |
| 317 SetStateLost(); | |
| 318 } | |
| OLD | NEW |