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 #if defined(OS_WIN) | 5 #if defined(OS_WIN) |
6 #include <windows.h> | 6 #include <windows.h> |
7 #endif | 7 #endif |
8 | 8 |
9 #include "content/common/gpu/gpu_channel.h" | 9 #include "content/common/gpu/gpu_channel.h" |
10 | 10 |
(...skipping 15 matching lines...) Expand all Loading... |
26 #endif | 26 #endif |
27 | 27 |
28 GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager, | 28 GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager, |
29 GpuWatchdog* watchdog, | 29 GpuWatchdog* watchdog, |
30 int renderer_id) | 30 int renderer_id) |
31 : gpu_channel_manager_(gpu_channel_manager), | 31 : gpu_channel_manager_(gpu_channel_manager), |
32 renderer_id_(renderer_id), | 32 renderer_id_(renderer_id), |
33 renderer_process_(base::kNullProcessHandle), | 33 renderer_process_(base::kNullProcessHandle), |
34 renderer_pid_(base::kNullProcessId), | 34 renderer_pid_(base::kNullProcessId), |
35 share_group_(new gfx::GLShareGroup), | 35 share_group_(new gfx::GLShareGroup), |
36 watchdog_(watchdog) { | 36 watchdog_(watchdog), |
| 37 task_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
37 DCHECK(gpu_channel_manager); | 38 DCHECK(gpu_channel_manager); |
38 DCHECK(renderer_id); | 39 DCHECK(renderer_id); |
39 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | 40 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
40 log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages); | 41 log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages); |
41 disallowed_extensions_.multisampling = | 42 disallowed_extensions_.multisampling = |
42 command_line->HasSwitch(switches::kDisableGLMultisampling); | 43 command_line->HasSwitch(switches::kDisableGLMultisampling); |
43 } | 44 } |
44 | 45 |
45 GpuChannel::~GpuChannel() { | 46 GpuChannel::~GpuChannel() { |
46 #if defined(OS_WIN) | 47 #if defined(OS_WIN) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 } | 80 } |
80 #endif | 81 #endif |
81 } | 82 } |
82 | 83 |
83 bool GpuChannel::OnMessageReceived(const IPC::Message& message) { | 84 bool GpuChannel::OnMessageReceived(const IPC::Message& message) { |
84 if (log_messages_) { | 85 if (log_messages_) { |
85 VLOG(1) << "received message @" << &message << " on channel @" << this | 86 VLOG(1) << "received message @" << &message << " on channel @" << this |
86 << " with type " << message.type(); | 87 << " with type " << message.type(); |
87 } | 88 } |
88 | 89 |
| 90 // Control messages are not deferred and can be handled out of order with |
| 91 // respect to routed ones. |
89 if (message.routing_id() == MSG_ROUTING_CONTROL) | 92 if (message.routing_id() == MSG_ROUTING_CONTROL) |
90 return OnControlMessageReceived(message); | 93 return OnControlMessageReceived(message); |
91 | 94 |
| 95 // If the channel is unscheduled, defer sync and async messages until it is |
| 96 // rescheduled. Also, even if the channel is scheduled, do not allow newly |
| 97 // received messages to be handled before previously received deferred ones; |
| 98 // append them to the deferred queue as well. |
| 99 if (!IsScheduled() || !deferred_messages_.empty()) { |
| 100 deferred_messages_.push(new IPC::Message(message)); |
| 101 return true; |
| 102 } |
| 103 |
92 if (!router_.RouteMessage(message)) { | 104 if (!router_.RouteMessage(message)) { |
93 // Respond to sync messages even if router failed to route. | 105 // Respond to sync messages even if router failed to route. |
94 if (message.is_sync()) { | 106 if (message.is_sync()) { |
95 IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message); | 107 IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message); |
96 reply->set_reply_error(); | 108 reply->set_reply_error(); |
97 Send(reply); | 109 Send(reply); |
98 } | 110 } |
99 return false; | 111 return false; |
100 } | 112 } |
101 | 113 |
| 114 // If the channel becomes unscheduled as a result of handling the message, |
| 115 // synthesize an IPC message to flush the command buffer that became |
| 116 // unscheduled. |
| 117 for (StubMap::Iterator<GpuCommandBufferStub> it(&stubs_); |
| 118 !it.IsAtEnd(); |
| 119 it.Advance()) { |
| 120 GpuCommandBufferStub* stub = it.GetCurrentValue(); |
| 121 if (!stub->IsScheduled()) { |
| 122 DCHECK(deferred_messages_.empty()); |
| 123 deferred_messages_.push(new GpuCommandBufferMsg_Rescheduled( |
| 124 stub->route_id())); |
| 125 } |
| 126 } |
| 127 |
102 return true; | 128 return true; |
103 } | 129 } |
104 | 130 |
105 void GpuChannel::OnChannelError() { | 131 void GpuChannel::OnChannelError() { |
106 gpu_channel_manager_->RemoveChannel(renderer_id_); | 132 gpu_channel_manager_->RemoveChannel(renderer_id_); |
107 } | 133 } |
108 | 134 |
109 void GpuChannel::OnChannelConnected(int32 peer_pid) { | 135 void GpuChannel::OnChannelConnected(int32 peer_pid) { |
110 renderer_pid_ = peer_pid; | 136 renderer_pid_ = peer_pid; |
111 } | 137 } |
112 | 138 |
113 bool GpuChannel::Send(IPC::Message* message) { | 139 bool GpuChannel::Send(IPC::Message* message) { |
114 // The GPU process must never send a synchronous IPC message to the renderer | 140 // The GPU process must never send a synchronous IPC message to the renderer |
115 // process. This could result in deadlock. | 141 // process. This could result in deadlock. |
116 DCHECK(!message->is_sync()); | 142 DCHECK(!message->is_sync()); |
117 if (log_messages_) { | 143 if (log_messages_) { |
118 VLOG(1) << "sending message @" << message << " on channel @" << this | 144 VLOG(1) << "sending message @" << message << " on channel @" << this |
119 << " with type " << message->type(); | 145 << " with type " << message->type(); |
120 } | 146 } |
121 | 147 |
122 if (!channel_.get()) { | 148 if (!channel_.get()) { |
123 delete message; | 149 delete message; |
124 return false; | 150 return false; |
125 } | 151 } |
126 | 152 |
127 return channel_->Send(message); | 153 return channel_->Send(message); |
128 } | 154 } |
129 | 155 |
| 156 bool GpuChannel::IsScheduled() { |
| 157 for (StubMap::Iterator<GpuCommandBufferStub> it(&stubs_); |
| 158 !it.IsAtEnd(); |
| 159 it.Advance()) { |
| 160 GpuCommandBufferStub* stub = it.GetCurrentValue(); |
| 161 if (!stub->IsScheduled()) |
| 162 return false; |
| 163 } |
| 164 |
| 165 return true; |
| 166 } |
| 167 |
| 168 void GpuChannel::OnScheduled() { |
| 169 // Post a task to handle any deferred messages. The deferred message queue is |
| 170 // not emptied here, which ensures that OnMessageReceived will continue to |
| 171 // defer newly received messages until the ones in the queue have all been |
| 172 // handled by HandleDeferredMessages. HandleDeferredMessages is invoked as a |
| 173 // task to prevent reentrancy. |
| 174 MessageLoop::current()->PostTask( |
| 175 FROM_HERE, |
| 176 task_factory_.NewRunnableMethod( |
| 177 &GpuChannel::HandleDeferredMessages)); |
| 178 } |
| 179 |
130 void GpuChannel::LoseAllContexts() { | 180 void GpuChannel::LoseAllContexts() { |
131 gpu_channel_manager_->LoseAllContexts(); | 181 gpu_channel_manager_->LoseAllContexts(); |
132 } | 182 } |
133 | 183 |
134 void GpuChannel::DestroySoon() { | 184 void GpuChannel::DestroySoon() { |
135 MessageLoop::current()->PostTask( | 185 MessageLoop::current()->PostTask( |
136 FROM_HERE, NewRunnableMethod(this, | 186 FROM_HERE, NewRunnableMethod(this, |
137 &GpuChannel::OnDestroy)); | 187 &GpuChannel::OnDestroy)); |
138 } | 188 } |
139 | 189 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 #endif | 261 #endif |
212 | 262 |
213 #if defined(OS_MACOSX) | 263 #if defined(OS_MACOSX) |
214 void GpuChannel::DestroyCommandBufferByViewId(int32 render_view_id) { | 264 void GpuChannel::DestroyCommandBufferByViewId(int32 render_view_id) { |
215 // This responds to a message from the browser process to destroy the command | 265 // This responds to a message from the browser process to destroy the command |
216 // buffer when the window with a GpuScheduler is closed (see | 266 // buffer when the window with a GpuScheduler is closed (see |
217 // RenderWidgetHostViewMac::DeallocFakePluginWindowHandle). Find the route id | 267 // RenderWidgetHostViewMac::DeallocFakePluginWindowHandle). Find the route id |
218 // that matches the given render_view_id and delete the route. | 268 // that matches the given render_view_id and delete the route. |
219 for (StubMap::const_iterator iter(&stubs_); !iter.IsAtEnd(); iter.Advance()) { | 269 for (StubMap::const_iterator iter(&stubs_); !iter.IsAtEnd(); iter.Advance()) { |
220 if (iter.GetCurrentValue()->render_view_id() == render_view_id) { | 270 if (iter.GetCurrentValue()->render_view_id() == render_view_id) { |
221 OnDestroyCommandBuffer(iter.GetCurrentKey()); | 271 OnDestroyCommandBuffer(iter.GetCurrentKey(), NULL); |
222 return; | 272 return; |
223 } | 273 } |
224 } | 274 } |
225 } | 275 } |
226 #endif | 276 #endif |
227 | 277 |
228 bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { | 278 bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { |
| 279 // Always use IPC_MESSAGE_HANDLER_DELAY_REPLY for synchronous message handlers |
| 280 // here. This is so the reply can be delayed if the scheduler is unscheduled. |
229 bool handled = true; | 281 bool handled = true; |
230 IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg) | 282 IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg) |
231 IPC_MESSAGE_HANDLER(GpuChannelMsg_Initialize, OnInitialize) | 283 IPC_MESSAGE_HANDLER(GpuChannelMsg_Initialize, OnInitialize) |
232 IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer, | 284 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuChannelMsg_CreateOffscreenCommandBuffer, |
233 OnCreateOffscreenCommandBuffer) | 285 OnCreateOffscreenCommandBuffer) |
234 IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer, | 286 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuChannelMsg_DestroyCommandBuffer, |
235 OnDestroyCommandBuffer) | 287 OnDestroyCommandBuffer) |
236 IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenSurface, | 288 IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuChannelMsg_CreateOffscreenSurface, |
237 OnCreateOffscreenSurface) | 289 OnCreateOffscreenSurface) |
238 IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroySurface, OnDestroySurface) | 290 IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroySurface, OnDestroySurface) |
239 IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateTransportTexture, | 291 IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateTransportTexture, |
240 OnCreateTransportTexture) | 292 OnCreateTransportTexture) |
241 IPC_MESSAGE_UNHANDLED(handled = false) | 293 IPC_MESSAGE_UNHANDLED(handled = false) |
242 IPC_END_MESSAGE_MAP() | 294 IPC_END_MESSAGE_MAP() |
243 DCHECK(handled) << msg.type(); | 295 DCHECK(handled) << msg.type(); |
244 return handled; | 296 return handled; |
245 } | 297 } |
246 | 298 |
| 299 void GpuChannel::HandleDeferredMessages() { |
| 300 // Empty the deferred queue so OnMessageRecieved does not defer on that |
| 301 // account and to prevent an infinite loop if the scheduler is unscheduled |
| 302 // as a result of handling already deferred messages. |
| 303 std::queue<IPC::Message*> deferred_messages_copy; |
| 304 std::swap(deferred_messages_copy, deferred_messages_); |
| 305 |
| 306 while (!deferred_messages_copy.empty()) { |
| 307 scoped_ptr<IPC::Message> message(deferred_messages_copy.front()); |
| 308 deferred_messages_copy.pop(); |
| 309 |
| 310 OnMessageReceived(*message); |
| 311 } |
| 312 } |
| 313 |
247 int GpuChannel::GenerateRouteID() { | 314 int GpuChannel::GenerateRouteID() { |
248 static int last_id = 0; | 315 static int last_id = 0; |
249 return ++last_id; | 316 return ++last_id; |
250 } | 317 } |
251 | 318 |
252 void GpuChannel::OnInitialize(base::ProcessHandle renderer_process) { | 319 void GpuChannel::OnInitialize(base::ProcessHandle renderer_process) { |
253 // Initialize should only happen once. | 320 // Initialize should only happen once. |
254 DCHECK(!renderer_process_); | 321 DCHECK(!renderer_process_); |
255 | 322 |
256 // Verify that the renderer has passed its own process handle. | 323 // Verify that the renderer has passed its own process handle. |
257 if (base::GetProcId(renderer_process) == renderer_pid_) | 324 if (base::GetProcId(renderer_process) == renderer_pid_) |
258 renderer_process_ = renderer_process; | 325 renderer_process_ = renderer_process; |
259 } | 326 } |
260 | 327 |
261 void GpuChannel::OnCreateOffscreenCommandBuffer( | 328 void GpuChannel::OnCreateOffscreenCommandBuffer( |
262 const gfx::Size& size, | 329 const gfx::Size& size, |
263 const GPUCreateCommandBufferConfig& init_params, | 330 const GPUCreateCommandBufferConfig& init_params, |
264 int32* route_id) { | 331 IPC::Message* reply_message) { |
| 332 int32 route_id = MSG_ROUTING_NONE; |
| 333 |
265 content::GetContentClient()->SetActiveURL(init_params.active_url); | 334 content::GetContentClient()->SetActiveURL(init_params.active_url); |
266 #if defined(ENABLE_GPU) | 335 #if defined(ENABLE_GPU) |
267 *route_id = GenerateRouteID(); | 336 route_id = GenerateRouteID(); |
268 | 337 |
269 scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub( | 338 scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub( |
270 this, | 339 this, |
271 gfx::kNullPluginWindow, | 340 gfx::kNullPluginWindow, |
272 size, | 341 size, |
273 disallowed_extensions_, | 342 disallowed_extensions_, |
274 init_params.allowed_extensions, | 343 init_params.allowed_extensions, |
275 init_params.attribs, | 344 init_params.attribs, |
276 *route_id, | 345 route_id, |
277 0, 0, watchdog_)); | 346 0, 0, watchdog_)); |
278 router_.AddRoute(*route_id, stub.get()); | 347 router_.AddRoute(route_id, stub.get()); |
279 stubs_.AddWithID(stub.release(), *route_id); | 348 stubs_.AddWithID(stub.release(), route_id); |
280 TRACE_EVENT1("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer", | 349 TRACE_EVENT1("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer", |
281 "route_id", route_id); | 350 "route_id", route_id); |
282 #else | |
283 *route_id = MSG_ROUTING_NONE; | |
284 #endif | 351 #endif |
| 352 |
| 353 GpuChannelMsg_CreateOffscreenCommandBuffer::WriteReplyParams( |
| 354 reply_message, |
| 355 route_id); |
| 356 Send(reply_message); |
285 } | 357 } |
286 | 358 |
287 void GpuChannel::OnDestroyCommandBuffer(int32 route_id) { | 359 void GpuChannel::OnDestroyCommandBuffer(int32 route_id, |
| 360 IPC::Message* reply_message) { |
288 #if defined(ENABLE_GPU) | 361 #if defined(ENABLE_GPU) |
289 TRACE_EVENT1("gpu", "GpuChannel::OnDestroyCommandBuffer", | 362 TRACE_EVENT1("gpu", "GpuChannel::OnDestroyCommandBuffer", |
290 "route_id", route_id); | 363 "route_id", route_id); |
291 if (router_.ResolveRoute(route_id)) { | 364 if (router_.ResolveRoute(route_id)) { |
292 GpuCommandBufferStub* stub = stubs_.Lookup(route_id); | |
293 // In case the renderer is currently blocked waiting for a sync reply from | |
294 // the stub, allow the stub to clean up and unblock pending messages here: | |
295 if (stub != NULL) | |
296 stub->CommandBufferWasDestroyed(); | |
297 router_.RemoveRoute(route_id); | 365 router_.RemoveRoute(route_id); |
298 stubs_.Remove(route_id); | 366 stubs_.Remove(route_id); |
299 } | 367 } |
300 #endif | 368 #endif |
| 369 |
| 370 if (reply_message) |
| 371 Send(reply_message); |
301 } | 372 } |
302 | 373 |
303 void GpuChannel::OnCreateOffscreenSurface(const gfx::Size& size, | 374 void GpuChannel::OnCreateOffscreenSurface(const gfx::Size& size, |
304 int* route_id) { | 375 IPC::Message* reply_message) { |
305 *route_id = MSG_ROUTING_NONE; | 376 int route_id = MSG_ROUTING_NONE; |
306 | 377 |
307 #if defined(ENABLE_GPU) | 378 #if defined(ENABLE_GPU) |
308 scoped_refptr<gfx::GLSurface> surface( | 379 scoped_refptr<gfx::GLSurface> surface( |
309 gfx::GLSurface::CreateOffscreenGLSurface(size)); | 380 gfx::GLSurface::CreateOffscreenGLSurface(size)); |
310 if (!surface.get()) | 381 if (!surface.get()) |
311 return; | 382 return; |
312 | 383 |
313 *route_id = GenerateRouteID(); | 384 route_id = GenerateRouteID(); |
314 | 385 |
315 scoped_ptr<GpuSurfaceStub> stub (new GpuSurfaceStub(this, | 386 scoped_ptr<GpuSurfaceStub> stub (new GpuSurfaceStub(this, |
316 *route_id, | 387 route_id, |
317 surface.release())); | 388 surface.release())); |
318 | 389 |
319 router_.AddRoute(*route_id, stub.get()); | 390 router_.AddRoute(route_id, stub.get()); |
320 surfaces_.AddWithID(stub.release(), *route_id); | 391 surfaces_.AddWithID(stub.release(), route_id); |
321 #endif | 392 #endif |
| 393 |
| 394 GpuChannelMsg_CreateOffscreenSurface::WriteReplyParams(reply_message, |
| 395 route_id); |
| 396 Send(reply_message); |
322 } | 397 } |
323 | 398 |
324 void GpuChannel::OnDestroySurface(int route_id) { | 399 void GpuChannel::OnDestroySurface(int route_id) { |
325 #if defined(ENABLE_GPU) | 400 #if defined(ENABLE_GPU) |
326 if (router_.ResolveRoute(route_id)) { | 401 if (router_.ResolveRoute(route_id)) { |
327 router_.RemoveRoute(route_id); | 402 router_.RemoveRoute(route_id); |
328 surfaces_.Remove(route_id); | 403 surfaces_.Remove(route_id); |
329 } | 404 } |
330 #endif | 405 #endif |
331 } | 406 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 | 448 |
374 #if defined(OS_POSIX) | 449 #if defined(OS_POSIX) |
375 int GpuChannel::GetRendererFileDescriptor() { | 450 int GpuChannel::GetRendererFileDescriptor() { |
376 int fd = -1; | 451 int fd = -1; |
377 if (channel_.get()) { | 452 if (channel_.get()) { |
378 fd = channel_->GetClientFileDescriptor(); | 453 fd = channel_->GetClientFileDescriptor(); |
379 } | 454 } |
380 return fd; | 455 return fd; |
381 } | 456 } |
382 #endif // defined(OS_POSIX) | 457 #endif // defined(OS_POSIX) |
OLD | NEW |