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 GpuMainThread : public base::Thread { |
| 124 public: |
| 125 explicit GpuMainThread(const std::string& channel_id) |
| 126 : base::Thread("Chrome_InProcGpuThread"), |
| 127 channel_id_(channel_id), |
| 128 gpu_process_(NULL), |
| 129 child_thread_(NULL) { |
| 130 } |
| 131 |
| 132 ~GpuMainThread() { |
| 133 Stop(); |
| 134 } |
| 135 |
| 136 protected: |
| 137 virtual void Init() { |
| 138 // TODO: Currently, ChildProcess supports only a single static instance, |
| 139 // which is a problem in --single-process mode, where both gpu and renderer |
| 140 // should be able to create separate instances. |
| 141 if (GpuProcess::current()) { |
| 142 child_thread_ = new GpuChildThread(channel_id_); |
| 143 } else { |
| 144 gpu_process_ = new GpuProcess(); |
| 145 // The process object takes ownership of the thread object, so do not |
| 146 // save and delete the pointer. |
| 147 gpu_process_->set_main_thread(new GpuChildThread(channel_id_)); |
| 148 } |
| 149 } |
| 150 |
| 151 virtual void CleanUp() { |
| 152 delete gpu_process_; |
| 153 if (child_thread_) |
| 154 delete child_thread_; |
| 155 } |
| 156 |
| 157 private: |
| 158 std::string channel_id_; |
| 159 // Deleted in CleanUp() on the gpu thread, so don't use smart pointers. |
| 160 GpuProcess* gpu_process_; |
| 161 GpuChildThread* child_thread_; |
| 162 |
| 163 DISALLOW_COPY_AND_ASSIGN(GpuMainThread); |
| 164 }; |
| 165 |
118 // static | 166 // static |
119 GpuProcessHost* GpuProcessHost::GetForRenderer( | 167 GpuProcessHost* GpuProcessHost::GetForRenderer( |
120 int renderer_id, content::CauseForGpuLaunch cause) { | 168 int renderer_id, content::CauseForGpuLaunch cause) { |
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
122 | 170 |
123 // Don't grant further access to GPU if it is not allowed. | 171 // Don't grant further access to GPU if it is not allowed. |
124 GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance(); | 172 GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance(); |
125 if (gpu_data_manager != NULL && !gpu_data_manager->GpuAccessAllowed()) | 173 if (gpu_data_manager != NULL && !gpu_data_manager->GpuAccessAllowed()) |
126 return NULL; | 174 return NULL; |
127 | 175 |
128 // The current policy is to ignore the renderer ID and use a single GPU | 176 // 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 | 177 // process for all renderers. Later this will be extended to allow the |
130 // use of multiple GPU processes. | 178 // use of multiple GPU processes. |
131 if (!g_hosts_by_id.IsEmpty()) { | 179 if (!g_hosts_by_id.IsEmpty()) { |
132 IDMap<GpuProcessHost>::iterator it(&g_hosts_by_id); | 180 IDMap<GpuProcessHost>::iterator it(&g_hosts_by_id); |
133 return it.GetCurrentValue(); | 181 return it.GetCurrentValue(); |
134 } | 182 } |
135 | 183 |
136 if (cause == content::CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH) | 184 if (cause == content::CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH) |
137 return NULL; | 185 return NULL; |
138 | 186 |
139 int host_id; | 187 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; | 188 host_id = ++g_last_host_id; |
163 | 189 |
164 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLaunchCause", | 190 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLaunchCause", |
165 cause, | 191 cause, |
166 content::CAUSE_FOR_GPU_LAUNCH_MAX_ENUM); | 192 content::CAUSE_FOR_GPU_LAUNCH_MAX_ENUM); |
167 | 193 |
168 GpuProcessHost* host = new GpuProcessHost(host_id); | 194 GpuProcessHost* host = new GpuProcessHost(host_id); |
169 if (host->Init()) | 195 if (host->Init()) |
170 return host; | 196 return host; |
171 | 197 |
(...skipping 17 matching lines...) Expand all Loading... |
189 | 215 |
190 if (host_id == 0) | 216 if (host_id == 0) |
191 return NULL; | 217 return NULL; |
192 | 218 |
193 return g_hosts_by_id.Lookup(host_id); | 219 return g_hosts_by_id.Lookup(host_id); |
194 } | 220 } |
195 | 221 |
196 GpuProcessHost::GpuProcessHost(int host_id) | 222 GpuProcessHost::GpuProcessHost(int host_id) |
197 : BrowserChildProcessHost(GPU_PROCESS), | 223 : BrowserChildProcessHost(GPU_PROCESS), |
198 host_id_(host_id), | 224 host_id_(host_id), |
199 gpu_process_(base::kNullProcessHandle) { | 225 gpu_process_(base::kNullProcessHandle), |
| 226 in_process_(false) { |
| 227 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) || |
| 228 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) |
| 229 in_process_ = true; |
| 230 |
| 231 // If the 'single GPU process' policy ever changes, we still want to maintain |
| 232 // it for 'gpu thread' mode and only create one instance of host and thread. |
| 233 DCHECK(!in_process_ || g_hosts_by_id.IsEmpty()); |
| 234 |
200 g_hosts_by_id.AddWithID(this, host_id_); | 235 g_hosts_by_id.AddWithID(this, host_id_); |
201 if (host_id == 0) | |
202 gpu_process_ = base::GetCurrentProcessHandle(); | |
203 | 236 |
204 // Post a task to create the corresponding GpuProcessHostUIShim. The | 237 // Post a task to create the corresponding GpuProcessHostUIShim. The |
205 // GpuProcessHostUIShim will be destroyed if either the browser exits, | 238 // GpuProcessHostUIShim will be destroyed if either the browser exits, |
206 // in which case it calls GpuProcessHostUIShim::DestroyAll, or the | 239 // in which case it calls GpuProcessHostUIShim::DestroyAll, or the |
207 // GpuProcessHost is destroyed, which happens when the corresponding GPU | 240 // GpuProcessHost is destroyed, which happens when the corresponding GPU |
208 // process terminates or fails to launch. | 241 // process terminates or fails to launch. |
209 BrowserThread::PostTask( | 242 BrowserThread::PostTask( |
210 BrowserThread::UI, | 243 BrowserThread::UI, |
211 FROM_HERE, | 244 FROM_HERE, |
212 NewRunnableFunction(&GpuProcessHostUIShim::Create, host_id)); | 245 NewRunnableFunction(&GpuProcessHostUIShim::Create, host_id)); |
(...skipping 17 matching lines...) Expand all Loading... |
230 BrowserThread::PostTask(BrowserThread::UI, | 263 BrowserThread::PostTask(BrowserThread::UI, |
231 FROM_HERE, | 264 FROM_HERE, |
232 NewRunnableFunction(GpuProcessHostUIShim::Destroy, | 265 NewRunnableFunction(GpuProcessHostUIShim::Destroy, |
233 host_id_)); | 266 host_id_)); |
234 } | 267 } |
235 | 268 |
236 bool GpuProcessHost::Init() { | 269 bool GpuProcessHost::Init() { |
237 if (!CreateChannel()) | 270 if (!CreateChannel()) |
238 return false; | 271 return false; |
239 | 272 |
240 if (!LaunchGpuProcess()) | 273 if (in_process_) { |
| 274 CommandLine::ForCurrentProcess()->AppendSwitch( |
| 275 switches::kDisableGpuWatchdog); |
| 276 |
| 277 in_process_gpu_thread_.reset(new GpuMainThread(channel_id())); |
| 278 |
| 279 base::Thread::Options options; |
| 280 #if defined(OS_WIN) |
| 281 // On Windows the GPU thread needs to pump the compositor child window's |
| 282 // message loop. TODO(apatrick): make this an IO thread if / when we get rid |
| 283 // of this child window. Unfortunately it might always be necessary for |
| 284 // Windows XP because we cannot share the backing store textures between |
| 285 // processes. |
| 286 options.message_loop_type = MessageLoop::TYPE_UI; |
| 287 #else |
| 288 options.message_loop_type = MessageLoop::TYPE_IO; |
| 289 #endif |
| 290 in_process_gpu_thread_->StartWithOptions(options); |
| 291 |
| 292 OnProcessLaunched(); // Fake a callback that the process is ready. |
| 293 } else if (!LaunchGpuProcess()) |
241 return false; | 294 return false; |
242 | 295 |
243 return Send(new GpuMsg_Initialize()); | 296 return Send(new GpuMsg_Initialize()); |
244 } | 297 } |
245 | 298 |
246 void GpuProcessHost::RouteOnUIThread(const IPC::Message& message) { | 299 void GpuProcessHost::RouteOnUIThread(const IPC::Message& message) { |
247 BrowserThread::PostTask( | 300 BrowserThread::PostTask( |
248 BrowserThread::UI, | 301 BrowserThread::UI, |
249 FROM_HERE, | 302 FROM_HERE, |
250 new RouteToGpuProcessHostUIShimTask(host_id_, message)); | 303 new RouteToGpuProcessHostUIShimTask(host_id_, message)); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 } | 473 } |
421 | 474 |
422 bool GpuProcessHost::CanShutdown() { | 475 bool GpuProcessHost::CanShutdown() { |
423 return true; | 476 return true; |
424 } | 477 } |
425 | 478 |
426 void GpuProcessHost::OnProcessLaunched() { | 479 void GpuProcessHost::OnProcessLaunched() { |
427 // Send the GPU process handle to the UI thread before it has to | 480 // 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 | 481 // respond to any requests to establish a GPU channel. The response |
429 // to such requests require that the GPU process handle be known. | 482 // to such requests require that the GPU process handle be known. |
| 483 |
| 484 base::ProcessHandle child_handle = in_process_ ? |
| 485 base::GetCurrentProcessHandle() : handle(); |
| 486 |
430 #if defined(OS_WIN) | 487 #if defined(OS_WIN) |
431 DuplicateHandle(base::GetCurrentProcessHandle(), | 488 DuplicateHandle(base::GetCurrentProcessHandle(), |
432 handle(), | 489 child_handle, |
433 base::GetCurrentProcessHandle(), | 490 base::GetCurrentProcessHandle(), |
434 &gpu_process_, | 491 &gpu_process_, |
435 PROCESS_DUP_HANDLE, | 492 PROCESS_DUP_HANDLE, |
436 FALSE, | 493 FALSE, |
437 0); | 494 0); |
438 #else | 495 #else |
439 gpu_process_ = handle(); | 496 gpu_process_ = child_handle; |
440 #endif | 497 #endif |
441 } | 498 } |
442 | 499 |
443 void GpuProcessHost::OnChildDied() { | 500 void GpuProcessHost::OnChildDied() { |
444 SendOutstandingReplies(); | 501 SendOutstandingReplies(); |
445 // Located in OnChildDied because OnProcessCrashed suffers from a race | 502 // Located in OnChildDied because OnProcessCrashed suffers from a race |
446 // condition on Linux. | 503 // condition on Linux. |
447 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", | 504 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", |
448 DIED_FIRST_TIME + g_gpu_crash_count, | 505 DIED_FIRST_TIME + g_gpu_crash_count, |
449 GPU_PROCESS_LIFETIME_EVENT_MAX); | 506 GPU_PROCESS_LIFETIME_EVENT_MAX); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
559 CreateCommandBufferCallback* callback, int32 route_id) { | 616 CreateCommandBufferCallback* callback, int32 route_id) { |
560 scoped_ptr<GpuProcessHost::CreateCommandBufferCallback> | 617 scoped_ptr<GpuProcessHost::CreateCommandBufferCallback> |
561 wrapped_callback(callback); | 618 wrapped_callback(callback); |
562 callback->Run(route_id); | 619 callback->Run(route_id); |
563 } | 620 } |
564 | 621 |
565 void GpuProcessHost::SynchronizeError(SynchronizeCallback* callback) { | 622 void GpuProcessHost::SynchronizeError(SynchronizeCallback* callback) { |
566 scoped_ptr<SynchronizeCallback> wrapped_callback(callback); | 623 scoped_ptr<SynchronizeCallback> wrapped_callback(callback); |
567 wrapped_callback->Run(); | 624 wrapped_callback->Run(); |
568 } | 625 } |
OLD | NEW |