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/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 |