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