OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/gpu/gpu_thread.h" | 5 #include "chrome/gpu/gpu_thread.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "app/gfx/gl/gl_context.h" | 10 #include "app/gfx/gl/gl_context.h" |
| 11 #include "app/gfx/gl/gl_implementation.h" |
11 #include "app/win/scoped_com_initializer.h" | 12 #include "app/win/scoped_com_initializer.h" |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "base/threading/worker_pool.h" | 14 #include "base/threading/worker_pool.h" |
14 #include "build/build_config.h" | 15 #include "build/build_config.h" |
15 #include "chrome/common/child_process.h" | 16 #include "chrome/common/child_process.h" |
16 #include "chrome/common/child_process_logging.h" | 17 #include "chrome/common/child_process_logging.h" |
| 18 #include "chrome/common/chrome_switches.h" |
17 #include "chrome/common/gpu_messages.h" | 19 #include "chrome/common/gpu_messages.h" |
18 #include "chrome/gpu/gpu_info_collector.h" | 20 #include "chrome/gpu/gpu_info_collector.h" |
| 21 #include "chrome/gpu/gpu_watchdog_thread.h" |
19 #include "ipc/ipc_channel_handle.h" | 22 #include "ipc/ipc_channel_handle.h" |
20 | 23 |
21 GpuThread::GpuThread() { | 24 #if defined(OS_MACOSX) |
| 25 #include "chrome/common/sandbox_mac.h" |
| 26 #endif |
| 27 |
| 28 const int kGpuTimeout = 10000; |
| 29 |
| 30 namespace { |
| 31 |
| 32 bool InitializeGpuSandbox() { |
| 33 #if defined(OS_MACOSX) |
| 34 CommandLine* parsed_command_line = CommandLine::ForCurrentProcess(); |
| 35 SandboxInitWrapper sandbox_wrapper; |
| 36 return sandbox_wrapper.InitializeSandbox(*parsed_command_line, |
| 37 switches::kGpuProcess); |
| 38 #else |
| 39 // TODO(port): Create GPU sandbox for linux and windows. |
| 40 return true; |
| 41 #endif |
22 } | 42 } |
23 | 43 |
| 44 } // namespace |
| 45 |
| 46 GpuThread::GpuThread(const CommandLine& command_line) |
| 47 : command_line_(command_line) {} |
| 48 |
24 GpuThread::~GpuThread() { | 49 GpuThread::~GpuThread() { |
25 } | 50 } |
26 | 51 |
27 void GpuThread::Init(const base::Time& process_start_time) { | 52 void GpuThread::Init(const base::Time& process_start_time) { |
28 gpu_info_collector::CollectGraphicsInfo(&gpu_info_); | 53 process_start_time_ = process_start_time; |
29 child_process_logging::SetGpuInfo(gpu_info_); | |
30 | |
31 #if defined(OS_WIN) | |
32 // Asynchronously collect the DirectX diagnostics because this can take a | |
33 // couple of seconds. | |
34 if (!base::WorkerPool::PostTask( | |
35 FROM_HERE, | |
36 NewRunnableFunction(&GpuThread::CollectDxDiagnostics, this), | |
37 true)) { | |
38 // Flag GPU info as complete if the DirectX diagnostics cannot be collected. | |
39 gpu_info_.SetProgress(GPUInfo::kComplete); | |
40 } | |
41 #endif | |
42 | |
43 // Record initialization only after collecting the GPU info because that can | |
44 // take a significant amount of time. | |
45 gpu_info_.SetInitializationTime(base::Time::Now() - process_start_time); | |
46 } | 54 } |
47 | 55 |
48 void GpuThread::RemoveChannel(int renderer_id) { | 56 void GpuThread::RemoveChannel(int renderer_id) { |
49 gpu_channels_.erase(renderer_id); | 57 gpu_channels_.erase(renderer_id); |
50 } | 58 } |
51 | 59 |
52 bool GpuThread::OnControlMessageReceived(const IPC::Message& msg) { | 60 bool GpuThread::OnControlMessageReceived(const IPC::Message& msg) { |
53 bool msg_is_ok = true; | 61 bool msg_is_ok = true; |
54 bool handled = true; | 62 bool handled = true; |
55 IPC_BEGIN_MESSAGE_MAP_EX(GpuThread, msg, msg_is_ok) | 63 IPC_BEGIN_MESSAGE_MAP_EX(GpuThread, msg, msg_is_ok) |
| 64 IPC_MESSAGE_HANDLER(GpuMsg_Initialize, OnInitialize) |
56 IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel) | 65 IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel) |
57 IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel) | 66 IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel) |
58 IPC_MESSAGE_HANDLER(GpuMsg_Synchronize, OnSynchronize) | 67 IPC_MESSAGE_HANDLER(GpuMsg_Synchronize, OnSynchronize) |
59 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo) | 68 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo) |
60 #if defined(OS_MACOSX) | 69 #if defined(OS_MACOSX) |
61 IPC_MESSAGE_HANDLER(GpuMsg_AcceleratedSurfaceBuffersSwappedACK, | 70 IPC_MESSAGE_HANDLER(GpuMsg_AcceleratedSurfaceBuffersSwappedACK, |
62 OnAcceleratedSurfaceBuffersSwappedACK) | 71 OnAcceleratedSurfaceBuffersSwappedACK) |
63 IPC_MESSAGE_HANDLER(GpuMsg_DidDestroyAcceleratedSurface, | 72 IPC_MESSAGE_HANDLER(GpuMsg_DidDestroyAcceleratedSurface, |
64 OnDidDestroyAcceleratedSurface) | 73 OnDidDestroyAcceleratedSurface) |
65 #endif | 74 #endif |
66 IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash) | 75 IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash) |
67 IPC_MESSAGE_HANDLER(GpuMsg_Hang, OnHang) | 76 IPC_MESSAGE_HANDLER(GpuMsg_Hang, OnHang) |
68 IPC_MESSAGE_UNHANDLED(handled = false) | 77 IPC_MESSAGE_UNHANDLED(handled = false) |
69 IPC_END_MESSAGE_MAP_EX() | 78 IPC_END_MESSAGE_MAP_EX() |
70 return handled; | 79 return handled; |
71 } | 80 } |
72 | 81 |
| 82 void GpuThread::OnInitialize() { |
| 83 // Load the GL implementation and locate the bindings before starting the GPU |
| 84 // watchdog because this can take a lot of time and the GPU watchdog might |
| 85 // terminate the GPU process. |
| 86 if (!gfx::GLContext::InitializeOneOff()) { |
| 87 MessageLoop::current()->Quit(); |
| 88 return; |
| 89 } |
| 90 gpu_info_collector::CollectGraphicsInfo(&gpu_info_); |
| 91 child_process_logging::SetGpuInfo(gpu_info_); |
| 92 |
| 93 #if defined(OS_WIN) |
| 94 // Asynchronously collect the DirectX diagnostics because this can take a |
| 95 // couple of seconds. |
| 96 if (!base::WorkerPool::PostTask( |
| 97 FROM_HERE, |
| 98 NewRunnableFunction(&GpuThread::CollectDxDiagnostics, this), |
| 99 true)) { |
| 100 // Flag GPU info as complete if the DirectX diagnostics cannot be collected. |
| 101 gpu_info_.SetProgress(GPUInfo::kComplete); |
| 102 } |
| 103 #endif |
| 104 |
| 105 // Record initialization only after collecting the GPU info because that can |
| 106 // take a significant amount of time. |
| 107 gpu_info_.SetInitializationTime(base::Time::Now() - process_start_time_); |
| 108 |
| 109 // Note that kNoSandbox will also disable the GPU sandbox. |
| 110 bool no_gpu_sandbox = command_line_.HasSwitch(switches::kNoGpuSandbox); |
| 111 if (!no_gpu_sandbox) { |
| 112 if (!InitializeGpuSandbox()) { |
| 113 LOG(ERROR) << "Failed to initialize the GPU sandbox"; |
| 114 MessageLoop::current()->Quit(); |
| 115 return; |
| 116 } |
| 117 } else { |
| 118 LOG(ERROR) << "Running without GPU sandbox"; |
| 119 } |
| 120 |
| 121 // In addition to disabling the watchdog if the command line switch is |
| 122 // present, disable it in two other cases. OSMesa is expected to run very |
| 123 // slowly. Also disable the watchdog on valgrind because the code is expected |
| 124 // to run slowly in that case. |
| 125 bool enable_watchdog = |
| 126 !command_line_.HasSwitch(switches::kDisableGpuWatchdog) && |
| 127 gfx::GetGLImplementation() != gfx::kGLImplementationOSMesaGL && |
| 128 !RunningOnValgrind(); |
| 129 |
| 130 // Disable the watchdog in debug builds because they tend to only be run by |
| 131 // developers who will not appreciate the watchdog killing the GPU process. |
| 132 #ifndef NDEBUG |
| 133 enable_watchdog = false; |
| 134 #endif |
| 135 |
| 136 // Disable the watchdog for Windows. It tends to abort when the GPU process |
| 137 // is not hung but still taking a long time to do something. Instead, the |
| 138 // browser process displays a dialog when it notices that the child window |
| 139 // is hung giving the user an opportunity to terminate it. This is the |
| 140 // same mechanism used to abort hung plugins. |
| 141 #if defined(OS_WIN) |
| 142 enable_watchdog = false; |
| 143 #endif |
| 144 |
| 145 // Start the GPU watchdog only after anything that is expected to be time |
| 146 // consuming has completed, otherwise the process is liable to be aborted. |
| 147 if (enable_watchdog) { |
| 148 watchdog_thread_ = new GpuWatchdogThread(kGpuTimeout); |
| 149 watchdog_thread_->Start(); |
| 150 } |
| 151 } |
| 152 |
| 153 void GpuThread::StopWatchdog() { |
| 154 if (watchdog_thread_.get()) { |
| 155 watchdog_thread_->Stop(); |
| 156 } |
| 157 } |
| 158 |
73 void GpuThread::OnEstablishChannel(int renderer_id) { | 159 void GpuThread::OnEstablishChannel(int renderer_id) { |
74 scoped_refptr<GpuChannel> channel; | 160 scoped_refptr<GpuChannel> channel; |
75 IPC::ChannelHandle channel_handle; | 161 IPC::ChannelHandle channel_handle; |
76 GPUInfo gpu_info; | 162 GPUInfo gpu_info; |
77 | 163 |
78 GpuChannelMap::const_iterator iter = gpu_channels_.find(renderer_id); | 164 GpuChannelMap::const_iterator iter = gpu_channels_.find(renderer_id); |
79 if (iter == gpu_channels_.end()) | 165 if (iter == gpu_channels_.end()) |
80 channel = new GpuChannel(renderer_id); | 166 channel = new GpuChannel(renderer_id); |
81 else | 167 else |
82 channel = iter->second; | 168 channel = iter->second; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 NewRunnableFunction(&GpuThread::SetDxDiagnostics, thread, node)); | 252 NewRunnableFunction(&GpuThread::SetDxDiagnostics, thread, node)); |
167 } | 253 } |
168 | 254 |
169 // Runs on the GPU thread. | 255 // Runs on the GPU thread. |
170 void GpuThread::SetDxDiagnostics(GpuThread* thread, const DxDiagNode& node) { | 256 void GpuThread::SetDxDiagnostics(GpuThread* thread, const DxDiagNode& node) { |
171 thread->gpu_info_.SetDxDiagnostics(node); | 257 thread->gpu_info_.SetDxDiagnostics(node); |
172 thread->gpu_info_.SetProgress(GPUInfo::kComplete); | 258 thread->gpu_info_.SetProgress(GPUInfo::kComplete); |
173 } | 259 } |
174 | 260 |
175 #endif | 261 #endif |
OLD | NEW |