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