Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/gpu/gpu_channel_host.h" | 5 #include "content/renderer/gpu/gpu_channel_host.h" |
| 6 | 6 |
| 7 #include "base/message_loop_proxy.h" | |
| 7 #include "content/common/child_process.h" | 8 #include "content/common/child_process.h" |
| 8 #include "content/common/gpu/gpu_messages.h" | 9 #include "content/common/gpu/gpu_messages.h" |
| 9 #include "content/renderer/gpu/command_buffer_proxy.h" | 10 #include "content/renderer/gpu/command_buffer_proxy.h" |
| 10 #include "content/renderer/gpu/gpu_surface_proxy.h" | 11 #include "content/renderer/gpu/gpu_surface_proxy.h" |
| 11 #include "content/renderer/gpu/transport_texture_service.h" | 12 #include "content/renderer/gpu/transport_texture_service.h" |
| 13 #include "content/renderer/render_process.h" | |
| 12 #include "content/renderer/render_thread.h" | 14 #include "content/renderer/render_thread.h" |
| 13 #include "googleurl/src/gurl.h" | 15 #include "googleurl/src/gurl.h" |
| 16 #include "ipc/ipc_sync_message_filter.h" | |
| 17 | |
| 18 using base::AutoLock; | |
| 19 using base::MessageLoopProxy; | |
| 20 | |
| 21 GpuChannelListener::GpuChannelListener() | |
| 22 : orphaned_(false), | |
| 23 loop_(MessageLoopProxy::current()) { | |
| 24 | |
| 25 } | |
| 26 | |
| 27 GpuChannelListener::~GpuChannelListener() { | |
| 28 | |
| 29 } | |
| 30 | |
| 31 GpuChannelHost::MessageFilter::MessageFilter(GpuChannelHost* parent) | |
| 32 : parent_(parent) { | |
| 33 DetachFromThread(); | |
| 34 } | |
| 35 | |
| 36 GpuChannelHost::MessageFilter::~MessageFilter() { | |
| 37 | |
| 38 } | |
| 39 | |
| 40 void GpuChannelHost::MessageFilter::AddRoute( | |
| 41 int route_id, | |
| 42 scoped_refptr<GpuChannelListener> listener) { | |
| 43 DCHECK(CalledOnValidThread()); | |
| 44 DCHECK(listeners_.find(route_id) == listeners_.end()); | |
| 45 listeners_[route_id] = listener; | |
| 46 } | |
| 47 | |
| 48 void GpuChannelHost::MessageFilter::RemoveRoute(int route_id) { | |
| 49 DCHECK(CalledOnValidThread()); | |
| 50 ListenerMap::iterator it = listeners_.find(route_id); | |
| 51 if (it != listeners_.end()) | |
| 52 listeners_.erase(it); | |
| 53 } | |
| 54 | |
| 55 bool GpuChannelHost::MessageFilter::OnMessageReceived( | |
| 56 const IPC::Message& message) { | |
| 57 DCHECK(CalledOnValidThread()); | |
| 58 | |
| 59 // Never handle sync message replies or we will deadlock here. | |
| 60 if (message.is_reply()) | |
| 61 return false; | |
| 62 | |
| 63 DCHECK(message.routing_id() != MSG_ROUTING_CONTROL); | |
| 64 | |
| 65 ListenerMap::iterator it = listeners_.find(message.routing_id()); | |
| 66 | |
| 67 if (it != listeners_.end()) { | |
| 68 const scoped_refptr<GpuChannelListener>& listener = it->second; | |
| 69 listener->loop()->PostTask( | |
| 70 FROM_HERE, | |
| 71 NewRunnableMethod( | |
| 72 listener.get(), | |
| 73 &GpuChannelListener::OnMessageReceived, | |
|
nduca
2011/08/15 22:28:36
i.e. post to DispatchMessage and check this->orpha
| |
| 74 message)); | |
| 75 } | |
| 76 | |
| 77 return true; | |
| 78 } | |
| 79 | |
| 80 void GpuChannelHost::MessageFilter::OnChannelError() { | |
| 81 DCHECK(CalledOnValidThread()); | |
| 82 | |
| 83 // Inform all the proxies that an error has occurred. This will be reported | |
| 84 // via OpenGL as a lost context. | |
| 85 for (ListenerMap::iterator it = listeners_.begin(); | |
| 86 it != listeners_.end(); | |
| 87 it++) { | |
| 88 const scoped_refptr<GpuChannelListener>& listener = it->second; | |
| 89 listener->loop()->PostTask( | |
| 90 FROM_HERE, | |
| 91 NewRunnableMethod( | |
| 92 listener.get(), | |
| 93 &GpuChannelListener::OnChannelError)); | |
| 94 } | |
| 95 | |
| 96 listeners_.clear(); | |
| 97 | |
| 98 ChildThread* main_thread = RenderProcess::current()->main_thread(); | |
| 99 MessageLoop* main_loop = main_thread->message_loop(); | |
| 100 main_loop->PostTask(FROM_HERE, | |
| 101 NewRunnableMethod(parent_, | |
| 102 &GpuChannelHost::OnChannelError)); | |
| 103 } | |
| 14 | 104 |
| 15 GpuChannelHost::GpuChannelHost() | 105 GpuChannelHost::GpuChannelHost() |
| 16 : state_(kUnconnected), | 106 : state_(kUnconnected), |
| 17 transport_texture_service_(new TransportTextureService()) { | 107 transport_texture_service_(new TransportTextureService()) { |
| 18 } | 108 } |
| 19 | 109 |
| 20 GpuChannelHost::~GpuChannelHost() { | 110 GpuChannelHost::~GpuChannelHost() { |
| 21 } | 111 } |
| 22 | 112 |
| 23 void GpuChannelHost::Connect( | 113 void GpuChannelHost::Connect( |
| 24 const IPC::ChannelHandle& channel_handle, | 114 const IPC::ChannelHandle& channel_handle, |
| 25 base::ProcessHandle renderer_process_for_gpu) { | 115 base::ProcessHandle renderer_process_for_gpu) { |
| 26 // Open a channel to the GPU process. | 116 DCHECK(RenderThread::current()); |
| 117 // Open a channel to the GPU process. We pass NULL as the main listener here | |
| 118 // since we need to filter everything to route it to the right thread. | |
| 27 channel_.reset(new IPC::SyncChannel( | 119 channel_.reset(new IPC::SyncChannel( |
| 28 channel_handle, IPC::Channel::MODE_CLIENT, this, | 120 channel_handle, IPC::Channel::MODE_CLIENT, NULL, |
| 29 ChildProcess::current()->io_message_loop_proxy(), true, | 121 ChildProcess::current()->io_message_loop_proxy(), true, |
| 30 ChildProcess::current()->GetShutDownEvent())); | 122 ChildProcess::current()->GetShutDownEvent())); |
| 31 | 123 |
| 124 sync_filter_.reset(new IPC::SyncMessageFilter( | |
| 125 ChildProcess::current()->GetShutDownEvent())); | |
| 126 | |
| 127 channel_->AddFilter(sync_filter_.get()); | |
| 128 | |
| 129 channel_->AddFilter(transport_texture_service_.get()); | |
| 130 | |
| 131 channel_filter_ = new MessageFilter(this); | |
| 132 | |
| 133 // Install the filter last, because we intercept all leftover | |
| 134 // messages. | |
| 135 channel_->AddFilter(channel_filter_.get()); | |
| 136 | |
| 32 // It is safe to send IPC messages before the channel completes the connection | 137 // It is safe to send IPC messages before the channel completes the connection |
| 33 // and receives the hello message from the GPU process. The messages get | 138 // and receives the hello message from the GPU process. The messages get |
| 34 // cached. | 139 // cached. |
| 35 state_ = kConnected; | 140 state_ = kConnected; |
| 36 | 141 |
| 37 // Notify the GPU process of our process handle. This gives it the ability | 142 // Notify the GPU process of our process handle. This gives it the ability |
| 38 // to map renderer handles into the GPU process. | 143 // to map renderer handles into the GPU process. |
| 39 Send(new GpuChannelMsg_Initialize(renderer_process_for_gpu)); | 144 Send(new GpuChannelMsg_Initialize(renderer_process_for_gpu)); |
| 40 } | 145 } |
| 41 | 146 |
| 42 void GpuChannelHost::set_gpu_info(const GPUInfo& gpu_info) { | 147 void GpuChannelHost::set_gpu_info(const GPUInfo& gpu_info) { |
| 43 gpu_info_ = gpu_info; | 148 gpu_info_ = gpu_info; |
| 44 } | 149 } |
| 45 | 150 |
| 46 const GPUInfo& GpuChannelHost::gpu_info() const { | 151 const GPUInfo& GpuChannelHost::gpu_info() const { |
| 47 return gpu_info_; | 152 return gpu_info_; |
| 48 } | 153 } |
| 49 | 154 |
| 50 void GpuChannelHost::SetStateLost() { | 155 void GpuChannelHost::SetStateLost() { |
| 51 state_ = kLost; | 156 state_ = kLost; |
| 52 } | 157 } |
| 53 | 158 |
| 54 bool GpuChannelHost::OnMessageReceived(const IPC::Message& message) { | |
| 55 DCHECK(message.routing_id() != MSG_ROUTING_CONTROL); | |
| 56 | |
| 57 return router_.RouteMessage(message); | |
| 58 } | |
| 59 | |
| 60 void GpuChannelHost::OnChannelConnected(int32 peer_pid) { | |
| 61 channel_->AddFilter(transport_texture_service_.get()); | |
| 62 } | |
| 63 | |
| 64 void GpuChannelHost::OnChannelError() { | 159 void GpuChannelHost::OnChannelError() { |
| 65 state_ = kLost; | 160 state_ = kLost; |
| 66 | 161 |
| 67 // Channel is invalid and will be reinitialized if this host is requested | 162 // Channel is invalid and will be reinitialized if this host is requested |
| 68 // again. | 163 // again. |
| 69 channel_.reset(); | 164 channel_.reset(); |
| 70 | |
| 71 // Inform all the proxies that an error has occured. This will be reported via | |
| 72 // OpenGL as a lost context. | |
| 73 for (ProxyMap::iterator iter = proxies_.begin(); | |
| 74 iter != proxies_.end(); iter++) { | |
| 75 router_.RemoveRoute(iter->first); | |
| 76 iter->second->OnChannelError(); | |
| 77 } | |
| 78 | |
| 79 // The proxies are reference counted so this will not result in their | |
| 80 // destruction if the client still holds a reference. The proxy will report | |
| 81 // a lost context, indicating to the client that it needs to be recreated. | |
| 82 proxies_.clear(); | |
| 83 } | 165 } |
| 84 | 166 |
| 85 bool GpuChannelHost::Send(IPC::Message* message) { | 167 bool GpuChannelHost::Send(IPC::Message* message) { |
| 86 // The GPU process never sends synchronous IPCs so clear the unblock flag to | 168 // The GPU process never sends synchronous IPCs so clear the unblock flag to |
| 87 // preserve order. | 169 // preserve order. |
| 88 message->set_unblock(false); | 170 message->set_unblock(false); |
| 89 if (channel_.get()) | 171 |
| 172 // Unfortunately a sync filter cannot be used on the main (listener) thread. | |
| 173 // TODO: Is that true even when we don't install a listener? | |
| 174 if (channel_.get() && RenderThread::current()) | |
| 90 return channel_->Send(message); | 175 return channel_->Send(message); |
| 176 else | |
| 177 return sync_filter_->Send(message); | |
| 91 | 178 |
| 92 // Callee takes ownership of message, regardless of whether Send is | 179 // Callee takes ownership of message, regardless of whether Send is |
| 93 // successful. See IPC::Message::Sender. | 180 // successful. See IPC::Message::Sender. |
| 94 delete message; | 181 delete message; |
| 95 return false; | 182 return false; |
| 96 } | 183 } |
| 97 | 184 |
| 98 CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer( | 185 scoped_refptr<CommandBufferProxy> GpuChannelHost::CreateViewCommandBuffer( |
| 99 int render_view_id, | 186 int render_view_id, |
| 100 CommandBufferProxy* share_group, | 187 CommandBufferProxy* share_group, |
| 101 const std::string& allowed_extensions, | 188 const std::string& allowed_extensions, |
| 102 const std::vector<int32>& attribs, | 189 const std::vector<int32>& attribs, |
| 103 const GURL& active_url) { | 190 const GURL& active_url) { |
| 104 #if defined(ENABLE_GPU) | 191 #if defined(ENABLE_GPU) |
| 192 AutoLock lock(context_lock_); | |
| 105 // An error occurred. Need to get the host again to reinitialize it. | 193 // An error occurred. Need to get the host again to reinitialize it. |
| 106 if (!channel_.get()) | 194 if (!channel_.get()) |
| 107 return NULL; | 195 return NULL; |
| 108 | 196 |
| 109 GPUCreateCommandBufferConfig init_params; | 197 GPUCreateCommandBufferConfig init_params; |
| 110 init_params.share_group_id = | 198 init_params.share_group_id = |
| 111 share_group ? share_group->route_id() : MSG_ROUTING_NONE; | 199 share_group ? share_group->route_id() : MSG_ROUTING_NONE; |
| 112 init_params.allowed_extensions = allowed_extensions; | 200 init_params.allowed_extensions = allowed_extensions; |
| 113 init_params.attribs = attribs; | 201 init_params.attribs = attribs; |
| 114 init_params.active_url = active_url; | 202 init_params.active_url = active_url; |
| 115 int32 route_id; | 203 int32 route_id; |
| 116 if (!RenderThread::current()->Send( | 204 if (!RenderThread::current()->Send( |
| 117 new GpuHostMsg_CreateViewCommandBuffer( | 205 new GpuHostMsg_CreateViewCommandBuffer( |
| 118 render_view_id, | 206 render_view_id, |
| 119 init_params, | 207 init_params, |
| 120 &route_id))) { | 208 &route_id))) { |
| 121 return NULL; | 209 return NULL; |
| 122 } | 210 } |
| 123 | 211 |
| 124 if (route_id == MSG_ROUTING_NONE) | 212 if (route_id == MSG_ROUTING_NONE) |
| 125 return NULL; | 213 return NULL; |
| 126 | 214 |
| 127 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id); | 215 scoped_refptr<CommandBufferProxy> command_buffer = |
| 128 router_.AddRoute(route_id, command_buffer); | 216 new CommandBufferProxy(this, route_id); |
| 217 AddRoute(route_id, command_buffer); | |
| 129 proxies_[route_id] = command_buffer; | 218 proxies_[route_id] = command_buffer; |
| 130 return command_buffer; | 219 return command_buffer; |
| 131 #else | 220 #else |
| 132 return NULL; | 221 return NULL; |
| 133 #endif | 222 #endif |
| 134 } | 223 } |
| 135 | 224 |
| 136 GpuVideoDecodeAcceleratorHost* GpuChannelHost::CreateVideoDecoder( | 225 GpuVideoDecodeAcceleratorHost* GpuChannelHost::CreateVideoDecoder( |
| 137 int command_buffer_route_id, | 226 int command_buffer_route_id, |
| 138 const std::vector<int32>& configs, | 227 const std::vector<int32>& configs, |
| 139 media::VideoDecodeAccelerator::Client* client) { | 228 media::VideoDecodeAccelerator::Client* client) { |
| 229 AutoLock lock(context_lock_); | |
| 140 ProxyMap::iterator it = proxies_.find(command_buffer_route_id); | 230 ProxyMap::iterator it = proxies_.find(command_buffer_route_id); |
| 141 DCHECK(it != proxies_.end()); | 231 DCHECK(it != proxies_.end()); |
| 142 CommandBufferProxy* proxy = it->second; | 232 CommandBufferProxy* proxy = it->second; |
| 143 return proxy->CreateVideoDecoder(configs, client); | 233 return proxy->CreateVideoDecoder(configs, client); |
| 144 } | 234 } |
| 145 | 235 |
| 146 CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer( | 236 scoped_refptr<CommandBufferProxy> GpuChannelHost::CreateOffscreenCommandBuffer( |
| 147 const gfx::Size& size, | 237 const gfx::Size& size, |
| 148 CommandBufferProxy* share_group, | 238 CommandBufferProxy* share_group, |
| 149 const std::string& allowed_extensions, | 239 const std::string& allowed_extensions, |
| 150 const std::vector<int32>& attribs, | 240 const std::vector<int32>& attribs, |
| 151 const GURL& active_url) { | 241 const GURL& active_url) { |
| 152 #if defined(ENABLE_GPU) | 242 #if defined(ENABLE_GPU) |
| 243 AutoLock lock(context_lock_); | |
| 153 // An error occurred. Need to get the host again to reinitialize it. | 244 // An error occurred. Need to get the host again to reinitialize it. |
| 154 if (!channel_.get()) | 245 if (!channel_.get()) |
| 155 return NULL; | 246 return NULL; |
| 156 | 247 |
| 157 GPUCreateCommandBufferConfig init_params; | 248 GPUCreateCommandBufferConfig init_params; |
| 158 init_params.share_group_id = | 249 init_params.share_group_id = |
| 159 share_group ? share_group->route_id() : MSG_ROUTING_NONE; | 250 share_group ? share_group->route_id() : MSG_ROUTING_NONE; |
| 160 init_params.allowed_extensions = allowed_extensions; | 251 init_params.allowed_extensions = allowed_extensions; |
| 161 init_params.attribs = attribs; | 252 init_params.attribs = attribs; |
| 162 init_params.active_url = active_url; | 253 init_params.active_url = active_url; |
| 163 int32 route_id; | 254 int32 route_id; |
| 164 if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size, | 255 if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size, |
| 165 init_params, | 256 init_params, |
| 166 &route_id))) { | 257 &route_id))) { |
| 167 return NULL; | 258 return NULL; |
| 168 } | 259 } |
| 169 | 260 |
| 170 if (route_id == MSG_ROUTING_NONE) | 261 if (route_id == MSG_ROUTING_NONE) |
| 171 return NULL; | 262 return NULL; |
| 172 | 263 |
| 173 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id); | 264 scoped_refptr<CommandBufferProxy> command_buffer = |
| 174 router_.AddRoute(route_id, command_buffer); | 265 new CommandBufferProxy(this, route_id); |
| 266 AddRoute(route_id, command_buffer); | |
| 175 proxies_[route_id] = command_buffer; | 267 proxies_[route_id] = command_buffer; |
| 176 return command_buffer; | 268 return command_buffer; |
| 177 #else | 269 #else |
| 178 return NULL; | 270 return NULL; |
| 179 #endif | 271 #endif |
| 180 } | 272 } |
| 181 | 273 |
| 182 void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) { | 274 void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) { |
| 183 #if defined(ENABLE_GPU) | 275 #if defined(ENABLE_GPU) |
| 276 AutoLock lock(context_lock_); | |
| 184 Send(new GpuChannelMsg_DestroyCommandBuffer(command_buffer->route_id())); | 277 Send(new GpuChannelMsg_DestroyCommandBuffer(command_buffer->route_id())); |
| 185 | 278 |
| 186 // Check the proxy has not already been removed after a channel error. | 279 // Check the proxy has not already been removed after a channel error. |
| 187 int route_id = command_buffer->route_id(); | 280 int route_id = command_buffer->route_id(); |
| 188 if (proxies_.find(command_buffer->route_id()) != proxies_.end()) { | 281 if (proxies_.find(command_buffer->route_id()) != proxies_.end()) |
| 189 proxies_.erase(route_id); | 282 proxies_.erase(route_id); |
| 190 router_.RemoveRoute(route_id); | 283 RemoveRoute(route_id); |
| 191 } | 284 command_buffer->Orphan(); |
| 192 | |
| 193 delete command_buffer; | |
| 194 #endif | 285 #endif |
| 195 } | 286 } |
| 196 | 287 |
| 197 GpuSurfaceProxy* GpuChannelHost::CreateOffscreenSurface(const gfx::Size& size) { | 288 scoped_refptr<GpuSurfaceProxy> GpuChannelHost::CreateOffscreenSurface( |
| 289 const gfx::Size& size) { | |
| 198 #if defined(ENABLE_GPU) | 290 #if defined(ENABLE_GPU) |
| 291 AutoLock lock(context_lock_); | |
| 199 int route_id; | 292 int route_id; |
| 200 if (!Send(new GpuChannelMsg_CreateOffscreenSurface(size, &route_id))) | 293 if (!Send(new GpuChannelMsg_CreateOffscreenSurface(size, &route_id))) |
| 201 return NULL; | 294 return NULL; |
| 202 | 295 |
| 203 scoped_ptr<GpuSurfaceProxy> surface(new GpuSurfaceProxy(this, route_id)); | 296 scoped_refptr<GpuSurfaceProxy> surface(new GpuSurfaceProxy(this, route_id)); |
| 204 router_.AddRoute(route_id, surface.get()); | 297 AddRoute(route_id, surface.get()); |
| 205 | 298 |
| 206 return surface.release(); | 299 return surface; |
| 207 #endif | 300 #endif |
| 208 } | 301 } |
| 209 | 302 |
| 210 void GpuChannelHost::DestroySurface(GpuSurfaceProxy* surface) { | 303 void GpuChannelHost::DestroySurface(GpuSurfaceProxy* surface) { |
| 211 #if defined(ENABLE_GPU) | 304 #if defined(ENABLE_GPU) |
| 305 AutoLock lock(context_lock_); | |
| 212 Send(new GpuChannelMsg_DestroySurface(surface->route_id())); | 306 Send(new GpuChannelMsg_DestroySurface(surface->route_id())); |
| 213 if (router_.ResolveRoute(surface->route_id())) | |
| 214 router_.RemoveRoute(surface->route_id()); | |
| 215 | 307 |
| 216 delete surface; | 308 RemoveRoute(surface->route_id()); |
| 309 surface->Orphan(); | |
| 217 #endif | 310 #endif |
| 218 } | 311 } |
| 312 | |
| 313 void GpuChannelHost::AddRoute( | |
| 314 int route_id, scoped_refptr<GpuChannelListener> listener) { | |
| 315 DCHECK(listener->loop() && listener->loop() == MessageLoopProxy::current()); | |
| 316 | |
| 317 MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy(); | |
| 318 io_loop->PostTask(FROM_HERE, | |
| 319 NewRunnableMethod( | |
| 320 channel_filter_.get(), | |
| 321 &GpuChannelHost::MessageFilter::AddRoute, | |
| 322 route_id, listener)); | |
| 323 } | |
| 324 | |
| 325 void GpuChannelHost::RemoveRoute(int route_id) { | |
| 326 MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy(); | |
| 327 io_loop->PostTask(FROM_HERE, | |
| 328 NewRunnableMethod( | |
| 329 channel_filter_.get(), | |
| 330 &GpuChannelHost::MessageFilter::RemoveRoute, | |
| 331 route_id)); | |
| 332 } | |
| OLD | NEW |