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/browser/gpu/gpu_process_host.h" | 5 #include "content/browser/gpu/gpu_process_host.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "base/memory/ref_counted.h" | 9 #include "base/memory/ref_counted.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/process_util.h" | 11 #include "base/process_util.h" |
12 #include "base/string_piece.h" | 12 #include "base/string_piece.h" |
13 #include "base/threading/thread.h" | |
13 #include "chrome/browser/tab_contents/render_view_host_delegate_helper.h" | 14 #include "chrome/browser/tab_contents/render_view_host_delegate_helper.h" |
14 #include "chrome/common/chrome_switches.h" | 15 #include "chrome/common/chrome_switches.h" |
15 #include "chrome/common/render_messages.h" | 16 #include "chrome/common/render_messages.h" |
16 #include "content/browser/browser_thread.h" | 17 #include "content/browser/browser_thread.h" |
17 #include "content/browser/gpu/gpu_data_manager.h" | 18 #include "content/browser/gpu/gpu_data_manager.h" |
18 #include "content/browser/gpu/gpu_process_host_ui_shim.h" | 19 #include "content/browser/gpu/gpu_process_host_ui_shim.h" |
19 #include "content/browser/renderer_host/render_widget_host.h" | 20 #include "content/browser/renderer_host/render_widget_host.h" |
20 #include "content/browser/renderer_host/render_widget_host_view.h" | 21 #include "content/browser/renderer_host/render_widget_host_view.h" |
21 #include "content/common/gpu/gpu_messages.h" | 22 #include "content/common/gpu/gpu_messages.h" |
23 #include "content/gpu/gpu_child_thread.h" | |
24 #include "content/gpu/gpu_process.h" | |
22 #include "ipc/ipc_channel_handle.h" | 25 #include "ipc/ipc_channel_handle.h" |
23 #include "ipc/ipc_switches.h" | 26 #include "ipc/ipc_switches.h" |
24 #include "media/base/media_switches.h" | 27 #include "media/base/media_switches.h" |
25 #include "ui/gfx/gl/gl_context.h" | 28 #include "ui/gfx/gl/gl_context.h" |
26 #include "ui/gfx/gl/gl_switches.h" | 29 #include "ui/gfx/gl/gl_switches.h" |
27 | 30 |
28 #if defined(OS_LINUX) | 31 #if defined(OS_LINUX) |
29 #include "ui/gfx/gtk_native_view_id_manager.h" | 32 #include "ui/gfx/gtk_native_view_id_manager.h" |
30 #endif // defined(OS_LINUX) | 33 #endif // defined(OS_LINUX) |
31 | 34 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
108 } | 111 } |
109 } | 112 } |
110 | 113 |
111 GpuProcessHost::SurfaceRef::~SurfaceRef() { | 114 GpuProcessHost::SurfaceRef::~SurfaceRef() { |
112 BrowserThread::PostTask(BrowserThread::UI, | 115 BrowserThread::PostTask(BrowserThread::UI, |
113 FROM_HERE, | 116 FROM_HERE, |
114 new ReleasePermanentXIDDispatcher(surface_)); | 117 new ReleasePermanentXIDDispatcher(surface_)); |
115 } | 118 } |
116 #endif // defined(OS_LINUX) | 119 #endif // defined(OS_LINUX) |
117 | 120 |
121 // This class creates a GPU thread (instead of a GPU process), when running | |
122 // with --in-process-gpu or --single-process. | |
123 class GpuThreadWrapper : public base::Thread { | |
124 public: | |
125 explicit GpuThreadWrapper(const std::string& channel_id) | |
126 : base::Thread("Chrome_InProcGpuThread"), | |
127 channel_id_(channel_id), | |
128 gpu_process_(NULL) { | |
129 } | |
130 | |
131 ~GpuThreadWrapper() { | |
132 Stop(); | |
133 } | |
134 | |
135 protected: | |
136 virtual void Init() { | |
137 // TODO: Currently, ChildProcess supports only a single static instance, | |
138 // which is a problem in --single-process mode, where both gpu and renderer | |
139 // should be able to create separate instances. | |
140 DCHECK(!GpuProcess::current()); | |
jam
2011/05/26 01:15:24
what happens if someone uses --single-process mode
Daniel Sievers (Google)
2011/05/26 01:35:09
Before this change, it would just not work (time o
| |
141 gpu_process_ = new GpuProcess(); | |
142 gpu_process_->set_main_thread(new GpuChildThread(channel_id_)); | |
143 } | |
144 | |
145 virtual void CleanUp() { | |
146 delete gpu_process_; | |
147 } | |
148 | |
149 private: | |
150 std::string channel_id_; | |
151 // Deleted in CleanUp() on the gpu thread, so don't use smart pointers. | |
152 GpuProcess* gpu_process_; | |
153 | |
154 DISALLOW_COPY_AND_ASSIGN(GpuThreadWrapper); | |
155 }; | |
156 | |
118 // static | 157 // static |
119 GpuProcessHost* GpuProcessHost::GetForRenderer( | 158 GpuProcessHost* GpuProcessHost::GetForRenderer( |
120 int renderer_id, content::CauseForGpuLaunch cause) { | 159 int renderer_id, content::CauseForGpuLaunch cause) { |
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
122 | 161 |
123 // Don't grant further access to GPU if it is not allowed. | 162 // Don't grant further access to GPU if it is not allowed. |
124 GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance(); | 163 GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance(); |
125 if (gpu_data_manager != NULL && !gpu_data_manager->GpuAccessAllowed()) | 164 if (gpu_data_manager != NULL && !gpu_data_manager->GpuAccessAllowed()) |
126 return NULL; | 165 return NULL; |
127 | 166 |
128 // The current policy is to ignore the renderer ID and use a single GPU | 167 // The current policy is to ignore the renderer ID and use a single GPU |
129 // process for all renderers. Later this will be extended to allow the | 168 // process for all renderers. Later this will be extended to allow the |
130 // use of multiple GPU processes. | 169 // use of multiple GPU processes. |
131 if (!g_hosts_by_id.IsEmpty()) { | 170 if (!g_hosts_by_id.IsEmpty()) { |
132 IDMap<GpuProcessHost>::iterator it(&g_hosts_by_id); | 171 IDMap<GpuProcessHost>::iterator it(&g_hosts_by_id); |
133 return it.GetCurrentValue(); | 172 return it.GetCurrentValue(); |
134 } | 173 } |
135 | 174 |
136 if (cause == content::CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH) | 175 if (cause == content::CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH) |
137 return NULL; | 176 return NULL; |
138 | 177 |
178 bool in_process = | |
jam
2011/05/26 01:15:24
can you move the in_process bits to inside of GpuP
| |
179 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) || | |
180 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU); | |
181 | |
182 // If the 'single GPU process' policy ever changes, we still want to maintain | |
183 // it for 'gpu thread' mode and only create one instance of host and thread. | |
184 DCHECK(!in_process || g_hosts_by_id.IsEmpty()); | |
185 | |
139 int host_id; | 186 int host_id; |
140 /* TODO(apatrick): this is currently broken because this function is called on | |
141 the IO thread from GpuMessageFilter, and we don't have an IO thread object | |
142 when running the GPU code in the browser at the moment. | |
143 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) || | |
144 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) { | |
145 if (!g_browser_process->gpu_thread()) | |
146 return NULL; | |
147 | |
148 // Initialize GL on the GPU thread. | |
149 // TODO(apatrick): Handle failure to initialize (asynchronously). | |
150 if (!BrowserThread::PostTask( | |
151 BrowserThread::GPU, | |
152 FROM_HERE, | |
153 NewRunnableFunction(&gfx::GLContext::InitializeOneOff))) { | |
154 return NULL; | |
155 } | |
156 | |
157 host_id = 0; | |
158 } else { | |
159 host_id = ++g_last_host_id; | |
160 } | |
161 */ | |
162 host_id = ++g_last_host_id; | 187 host_id = ++g_last_host_id; |
163 | 188 |
164 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLaunchCause", | 189 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLaunchCause", |
165 cause, | 190 cause, |
166 content::CAUSE_FOR_GPU_LAUNCH_MAX_ENUM); | 191 content::CAUSE_FOR_GPU_LAUNCH_MAX_ENUM); |
167 | 192 |
168 GpuProcessHost* host = new GpuProcessHost(host_id); | 193 GpuProcessHost* host = new GpuProcessHost(host_id, in_process); |
169 if (host->Init()) | 194 if (host->Init()) |
170 return host; | 195 return host; |
171 | 196 |
172 delete host; | 197 delete host; |
173 return NULL; | 198 return NULL; |
174 } | 199 } |
175 | 200 |
176 // static | 201 // static |
177 void GpuProcessHost::SendOnIO(int renderer_id, | 202 void GpuProcessHost::SendOnIO(int renderer_id, |
178 content::CauseForGpuLaunch cause, | 203 content::CauseForGpuLaunch cause, |
179 IPC::Message* message) { | 204 IPC::Message* message) { |
180 BrowserThread::PostTask( | 205 BrowserThread::PostTask( |
181 BrowserThread::IO, FROM_HERE, | 206 BrowserThread::IO, FROM_HERE, |
182 NewRunnableFunction( | 207 NewRunnableFunction( |
183 &SendGpuProcessMessage, renderer_id, cause, message)); | 208 &SendGpuProcessMessage, renderer_id, cause, message)); |
184 } | 209 } |
185 | 210 |
186 // static | 211 // static |
187 GpuProcessHost* GpuProcessHost::FromID(int host_id) { | 212 GpuProcessHost* GpuProcessHost::FromID(int host_id) { |
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
189 | 214 |
190 if (host_id == 0) | 215 if (host_id == 0) |
191 return NULL; | 216 return NULL; |
192 | 217 |
193 return g_hosts_by_id.Lookup(host_id); | 218 return g_hosts_by_id.Lookup(host_id); |
194 } | 219 } |
195 | 220 |
196 GpuProcessHost::GpuProcessHost(int host_id) | 221 GpuProcessHost::GpuProcessHost(int host_id, bool in_process) |
197 : BrowserChildProcessHost(GPU_PROCESS), | 222 : BrowserChildProcessHost(GPU_PROCESS), |
198 host_id_(host_id), | 223 host_id_(host_id), |
199 gpu_process_(base::kNullProcessHandle) { | 224 gpu_process_(base::kNullProcessHandle), |
225 in_process_(in_process) { | |
200 g_hosts_by_id.AddWithID(this, host_id_); | 226 g_hosts_by_id.AddWithID(this, host_id_); |
201 if (host_id == 0) | 227 if (host_id == 0) |
202 gpu_process_ = base::GetCurrentProcessHandle(); | 228 gpu_process_ = base::GetCurrentProcessHandle(); |
203 | 229 |
204 // Post a task to create the corresponding GpuProcessHostUIShim. The | 230 // Post a task to create the corresponding GpuProcessHostUIShim. The |
205 // GpuProcessHostUIShim will be destroyed if either the browser exits, | 231 // GpuProcessHostUIShim will be destroyed if either the browser exits, |
206 // in which case it calls GpuProcessHostUIShim::DestroyAll, or the | 232 // in which case it calls GpuProcessHostUIShim::DestroyAll, or the |
207 // GpuProcessHost is destroyed, which happens when the corresponding GPU | 233 // GpuProcessHost is destroyed, which happens when the corresponding GPU |
208 // process terminates or fails to launch. | 234 // process terminates or fails to launch. |
209 BrowserThread::PostTask( | 235 BrowserThread::PostTask( |
(...skipping 20 matching lines...) Expand all Loading... | |
230 BrowserThread::PostTask(BrowserThread::UI, | 256 BrowserThread::PostTask(BrowserThread::UI, |
231 FROM_HERE, | 257 FROM_HERE, |
232 NewRunnableFunction(GpuProcessHostUIShim::Destroy, | 258 NewRunnableFunction(GpuProcessHostUIShim::Destroy, |
233 host_id_)); | 259 host_id_)); |
234 } | 260 } |
235 | 261 |
236 bool GpuProcessHost::Init() { | 262 bool GpuProcessHost::Init() { |
237 if (!CreateChannel()) | 263 if (!CreateChannel()) |
238 return false; | 264 return false; |
239 | 265 |
240 if (!LaunchGpuProcess()) | 266 if (in_process_) { |
267 CommandLine::ForCurrentProcess()->AppendSwitch( | |
268 switches::kDisableGpuWatchdog); | |
269 | |
270 in_process_gpu_thread_.reset(new GpuThreadWrapper(channel_id())); | |
271 | |
272 base::Thread::Options options; | |
273 #if defined(OS_WIN) | |
274 // On Windows the GPU thread needs to pump the compositor child window's | |
275 // message loop. TODO(apatrick): make this an IO thread if / when we get rid | |
276 // of this child window. Unfortunately it might always be necessary for | |
277 // Windows XP because we cannot share the backing store textures between | |
278 // processes. | |
279 options.message_loop_type = MessageLoop::TYPE_UI; | |
280 #else | |
281 options.message_loop_type = MessageLoop::TYPE_IO; | |
282 #endif | |
283 in_process_gpu_thread_->StartWithOptions(options); | |
284 | |
285 OnProcessLaunched(); // Fake a callback that the process is ready. | |
286 } else if (!LaunchGpuProcess()) | |
241 return false; | 287 return false; |
242 | 288 |
243 return Send(new GpuMsg_Initialize()); | 289 return Send(new GpuMsg_Initialize()); |
244 } | 290 } |
245 | 291 |
246 void GpuProcessHost::RouteOnUIThread(const IPC::Message& message) { | 292 void GpuProcessHost::RouteOnUIThread(const IPC::Message& message) { |
247 BrowserThread::PostTask( | 293 BrowserThread::PostTask( |
248 BrowserThread::UI, | 294 BrowserThread::UI, |
249 FROM_HERE, | 295 FROM_HERE, |
250 new RouteToGpuProcessHostUIShimTask(host_id_, message)); | 296 new RouteToGpuProcessHostUIShimTask(host_id_, message)); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 } | 466 } |
421 | 467 |
422 bool GpuProcessHost::CanShutdown() { | 468 bool GpuProcessHost::CanShutdown() { |
423 return true; | 469 return true; |
424 } | 470 } |
425 | 471 |
426 void GpuProcessHost::OnProcessLaunched() { | 472 void GpuProcessHost::OnProcessLaunched() { |
427 // Send the GPU process handle to the UI thread before it has to | 473 // Send the GPU process handle to the UI thread before it has to |
428 // respond to any requests to establish a GPU channel. The response | 474 // respond to any requests to establish a GPU channel. The response |
429 // to such requests require that the GPU process handle be known. | 475 // to such requests require that the GPU process handle be known. |
476 | |
477 base::ProcessHandle child_handle = in_process_ ? | |
478 base::GetCurrentProcessHandle() : handle(); | |
479 | |
430 #if defined(OS_WIN) | 480 #if defined(OS_WIN) |
431 DuplicateHandle(base::GetCurrentProcessHandle(), | 481 DuplicateHandle(base::GetCurrentProcessHandle(), |
432 handle(), | 482 child_handle, |
433 base::GetCurrentProcessHandle(), | 483 base::GetCurrentProcessHandle(), |
434 &gpu_process_, | 484 &gpu_process_, |
435 PROCESS_DUP_HANDLE, | 485 PROCESS_DUP_HANDLE, |
436 FALSE, | 486 FALSE, |
437 0); | 487 0); |
438 #else | 488 #else |
439 gpu_process_ = handle(); | 489 gpu_process_ = child_handle; |
440 #endif | 490 #endif |
441 } | 491 } |
442 | 492 |
443 void GpuProcessHost::OnChildDied() { | 493 void GpuProcessHost::OnChildDied() { |
444 SendOutstandingReplies(); | 494 SendOutstandingReplies(); |
445 // Located in OnChildDied because OnProcessCrashed suffers from a race | 495 // Located in OnChildDied because OnProcessCrashed suffers from a race |
446 // condition on Linux. | 496 // condition on Linux. |
447 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", | 497 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", |
448 DIED_FIRST_TIME + g_gpu_crash_count, | 498 DIED_FIRST_TIME + g_gpu_crash_count, |
449 GPU_PROCESS_LIFETIME_EVENT_MAX); | 499 GPU_PROCESS_LIFETIME_EVENT_MAX); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
559 CreateCommandBufferCallback* callback, int32 route_id) { | 609 CreateCommandBufferCallback* callback, int32 route_id) { |
560 scoped_ptr<GpuProcessHost::CreateCommandBufferCallback> | 610 scoped_ptr<GpuProcessHost::CreateCommandBufferCallback> |
561 wrapped_callback(callback); | 611 wrapped_callback(callback); |
562 callback->Run(route_id); | 612 callback->Run(route_id); |
563 } | 613 } |
564 | 614 |
565 void GpuProcessHost::SynchronizeError(SynchronizeCallback* callback) { | 615 void GpuProcessHost::SynchronizeError(SynchronizeCallback* callback) { |
566 scoped_ptr<SynchronizeCallback> wrapped_callback(callback); | 616 scoped_ptr<SynchronizeCallback> wrapped_callback(callback); |
567 wrapped_callback->Run(); | 617 wrapped_callback->Run(); |
568 } | 618 } |
OLD | NEW |