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