OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <stddef.h> | 5 #include <stddef.h> |
6 #include <stdlib.h> | 6 #include <stdlib.h> |
7 | 7 |
8 #include <memory> | 8 #include <memory> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/lazy_instance.h" | |
12 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
13 #include "base/metrics/histogram.h" | |
14 #include "base/metrics/statistics_recorder.h" | |
15 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
16 #include "base/run_loop.h" | 13 #include "base/run_loop.h" |
17 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
18 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
19 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 16 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
20 #include "base/threading/platform_thread.h" | 17 #include "base/threading/platform_thread.h" |
21 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
22 #include "build/build_config.h" | 19 #include "build/build_config.h" |
23 #include "content/child/child_process.h" | 20 #include "content/child/child_process.h" |
24 #include "content/common/content_constants_internal.h" | 21 #include "content/common/content_constants_internal.h" |
25 #include "content/common/gpu_host_messages.h" | |
26 #include "content/common/sandbox_linux/sandbox_linux.h" | 22 #include "content/common/sandbox_linux/sandbox_linux.h" |
27 #include "content/gpu/gpu_child_thread.h" | 23 #include "content/gpu/gpu_child_thread.h" |
28 #include "content/gpu/gpu_process.h" | 24 #include "content/gpu/gpu_process.h" |
29 #include "content/public/common/content_client.h" | 25 #include "content/public/common/content_client.h" |
30 #include "content/public/common/content_switches.h" | 26 #include "content/public/common/content_switches.h" |
31 #include "content/public/common/main_function_params.h" | 27 #include "content/public/common/main_function_params.h" |
32 #include "gpu/command_buffer/service/gpu_switches.h" | 28 #include "gpu/command_buffer/service/gpu_switches.h" |
33 #include "gpu/config/gpu_info_collector.h" | 29 #include "gpu/config/gpu_info_collector.h" |
34 #include "gpu/config/gpu_switches.h" | |
35 #include "gpu/config/gpu_util.h" | |
36 #include "gpu/ipc/common/gpu_memory_buffer_support.h" | |
37 #include "gpu/ipc/service/gpu_config.h" | 30 #include "gpu/ipc/service/gpu_config.h" |
38 #include "gpu/ipc/service/gpu_memory_buffer_factory.h" | 31 #include "gpu/ipc/service/gpu_init.h" |
| 32 #include "gpu/ipc/service/gpu_init_delegate.h" |
39 #include "gpu/ipc/service/gpu_watchdog_thread.h" | 33 #include "gpu/ipc/service/gpu_watchdog_thread.h" |
40 #include "ui/events/platform/platform_event_source.h" | 34 #include "ui/events/platform/platform_event_source.h" |
41 #include "ui/gl/gl_context.h" | |
42 #include "ui/gl/gl_implementation.h" | |
43 #include "ui/gl/gl_surface.h" | |
44 #include "ui/gl/gl_switches.h" | |
45 #include "ui/gl/gpu_switching_manager.h" | |
46 #include "ui/gl/init/gl_factory.h" | |
47 | 35 |
48 #if defined(OS_WIN) | 36 #if defined(OS_WIN) |
49 #include <windows.h> | 37 #include <windows.h> |
50 #include <dwmapi.h> | 38 #include <dwmapi.h> |
51 #endif | 39 #endif |
52 | 40 |
53 #if defined(OS_ANDROID) | 41 #if defined(OS_ANDROID) |
54 #include "base/trace_event/memory_dump_manager.h" | 42 #include "base/trace_event/memory_dump_manager.h" |
55 #include "components/tracing/common/graphics_memory_dump_provider_android.h" | 43 #include "components/tracing/common/graphics_memory_dump_provider_android.h" |
56 #endif | 44 #endif |
57 | 45 |
58 #if defined(OS_WIN) | 46 #if defined(OS_WIN) |
59 #include "base/win/scoped_com_initializer.h" | 47 #include "base/win/scoped_com_initializer.h" |
60 #include "base/win/windows_version.h" | 48 #include "base/win/windows_version.h" |
61 #include "media/gpu/dxva_video_decode_accelerator_win.h" | 49 #include "media/gpu/dxva_video_decode_accelerator_win.h" |
62 #include "media/gpu/media_foundation_video_encode_accelerator_win.h" | 50 #include "media/gpu/media_foundation_video_encode_accelerator_win.h" |
63 #include "sandbox/win/src/sandbox.h" | 51 #include "sandbox/win/src/sandbox.h" |
64 #endif | 52 #endif |
65 | 53 |
66 #if defined(USE_X11) | 54 #if defined(USE_X11) |
67 #include "ui/base/x/x11_util.h" // nogncheck | |
68 #include "ui/gfx/x/x11_switches.h" // nogncheck | 55 #include "ui/gfx/x/x11_switches.h" // nogncheck |
69 #endif | 56 #endif |
70 | 57 |
71 #if defined(OS_LINUX) | 58 #if defined(OS_LINUX) |
72 #include "content/public/common/sandbox_init.h" | 59 #include "content/public/common/sandbox_init.h" |
73 #endif | 60 #endif |
74 | 61 |
75 #if defined(OS_MACOSX) | 62 #if defined(OS_MACOSX) |
76 #include "base/message_loop/message_pump_mac.h" | 63 #include "base/message_loop/message_pump_mac.h" |
77 #include "content/common/sandbox_mac.h" | 64 #include "content/common/sandbox_mac.h" |
78 #endif | 65 #endif |
79 | 66 |
80 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) | 67 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) |
81 #include "media/gpu/vaapi_wrapper.h" | 68 #include "media/gpu/vaapi_wrapper.h" |
82 #endif | 69 #endif |
83 | 70 |
84 #if defined(SANITIZER_COVERAGE) | 71 #if defined(SANITIZER_COVERAGE) |
85 #include <sanitizer/common_interface_defs.h> | 72 #include <sanitizer/common_interface_defs.h> |
86 #include <sanitizer/coverage_interface.h> | 73 #include <sanitizer/coverage_interface.h> |
87 #endif | 74 #endif |
88 | 75 |
89 namespace content { | 76 namespace content { |
90 | 77 |
91 namespace { | 78 namespace { |
92 | 79 |
93 void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info, | |
94 const base::CommandLine& command_line); | |
95 void WarmUpSandbox(); | |
96 | |
97 #if !defined(OS_MACOSX) | |
98 bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info); | |
99 #endif | |
100 | |
101 #if defined(OS_LINUX) | 80 #if defined(OS_LINUX) |
102 #if !defined(OS_CHROMEOS) | |
103 bool CanAccessNvidiaDeviceFile(); | |
104 #endif | |
105 bool StartSandboxLinux(const gpu::GPUInfo&, gpu::GpuWatchdogThread*); | 81 bool StartSandboxLinux(const gpu::GPUInfo&, gpu::GpuWatchdogThread*); |
106 #elif defined(OS_WIN) | 82 #elif defined(OS_WIN) |
107 bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo*); | 83 bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo*); |
108 #endif | 84 #endif |
109 | 85 |
110 base::LazyInstance<GpuChildThread::DeferredMessages> deferred_messages = | 86 class ContentGpuInitDelegate : public gpu::GpuInitDelegate { |
111 LAZY_INSTANCE_INITIALIZER; | 87 public: |
| 88 explicit ContentGpuInitDelegate(const base::CommandLine* command_line) |
| 89 : command_line_(command_line), watchdog_thread_(nullptr) { |
| 90 DCHECK(command_line_); |
| 91 } |
| 92 ~ContentGpuInitDelegate() override {} |
112 | 93 |
113 bool GpuProcessLogMessageHandler(int severity, | 94 #if defined(OS_WIN) |
114 const char* file, int line, | 95 void set_sandbox_info(sandbox::SandboxInterfaceInfo* sandbox_info) { |
115 size_t message_start, | 96 sandbox_info_ = sandbox_info; |
116 const std::string& str) { | 97 } |
117 std::string header = str.substr(0, message_start); | 98 #endif |
118 std::string message = str.substr(message_start); | 99 |
119 deferred_messages.Get().push( | 100 private: |
120 new GpuHostMsg_OnLogMessage(severity, header, message)); | 101 // gpu::GpuInit::Delegate: |
121 return false; | 102 void OnGpuInfoUpdate(const gpu::GPUInfo& gpu_info) override { |
122 } | 103 gpu_info_ = gpu_info; |
| 104 GetContentClient()->SetGpuInfo(gpu_info_); |
| 105 } |
| 106 |
| 107 void OnGpuWatchdogThreadCreated(gpu::GpuWatchdogThread* thread) override { |
| 108 watchdog_thread_ = thread; |
| 109 } |
| 110 |
| 111 void OnGpuWatchdogThreadDestroyed() override { watchdog_thread_ = nullptr; } |
| 112 |
| 113 bool ShouldInitializeGL() override { |
| 114 #if defined(OS_MACOSX) |
| 115 // On Mac, if the sandbox is enabled, then gl::init::InitializeGLOneOff() |
| 116 // is called from the sandbox warmup code before getting here. |
| 117 if (!command_line_->HasSwitch(switches::kNoSandbox)) |
| 118 return false; |
| 119 #endif |
| 120 if (command_line_->HasSwitch(switches::kInProcessGPU)) { |
| 121 // With in-process GPU, gl::init::InitializeGLOneOff() is called from |
| 122 // GpuChildThread before getting here. |
| 123 return false; |
| 124 } |
| 125 return true; |
| 126 } |
| 127 |
| 128 void WaitForDebugger() override { ChildProcess::WaitForDebugger("Gpu"); } |
| 129 |
| 130 void InitializeMessageLoop() override { |
| 131 #if defined(OS_WIN) |
| 132 // Use a UI message loop because ANGLE and the desktop GL platform can |
| 133 // create child windows to render to. |
| 134 base::MessagePumpForGpu::InitFactory(); |
| 135 message_loop_ = |
| 136 base::MakeUnique<base::MessageLoop>(base::MessageLoop::TYPE_UI); |
| 137 #elif defined(OS_LINUX) && defined(USE_X11) |
| 138 // We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX |
| 139 // and https://crbug.com/326995. |
| 140 message_loop_ = |
| 141 base::MakeUnique<base::MessageLoop>(base::MessageLoop::TYPE_UI); |
| 142 std::unique_ptr<ui::PlatformEventSource> event_source = |
| 143 ui::PlatformEventSource::CreateDefault(); |
| 144 #elif defined(OS_LINUX) |
| 145 message_loop_ = |
| 146 base::MakeUnique<base::MessageLoop>(base::MessageLoop::TYPE_DEFAULT); |
| 147 #elif defined(OS_MACOSX) |
| 148 // This is necessary for CoreAnimation layers hosted in the GPU process to |
| 149 // be |
| 150 // drawn. See http://crbug.com/312462. |
| 151 std::unique_ptr<base::MessagePump> pump(new base::MessagePumpCFRunLoop()); |
| 152 message_loop_ = base::MakeUnique<base::MessageLoop>(std::move(pump)); |
| 153 #else |
| 154 message_loop_ = |
| 155 base::MakeUnique<base::MessageLoop>(base::MessageLoop::TYPE_IO); |
| 156 #endif |
| 157 } |
| 158 |
| 159 void PreSandboxInitialization() override { |
| 160 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) |
| 161 media::VaapiWrapper::PreSandboxInitialization(); |
| 162 #endif |
| 163 } |
| 164 |
| 165 bool ShouldStartSandboxEarly() override { |
| 166 #if defined(OS_LINUX) |
| 167 // On Chrome OS ARM Mali, GPU driver userspace creates threads when |
| 168 // initializing a GL context, so start the sandbox early. |
| 169 return command_line_->HasSwitch(switches::kGpuSandboxStartEarly); |
| 170 #else |
| 171 return false; |
| 172 #endif |
| 173 } |
| 174 |
| 175 void WarmUpSandbox() override { |
| 176 #if defined(OS_WIN) |
| 177 media::DXVAVideoDecodeAccelerator::PreSandboxInitialization(); |
| 178 media::MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization(); |
| 179 #endif |
| 180 } |
| 181 |
| 182 bool StartSandbox() override { |
| 183 #if defined(OS_LINUX) |
| 184 return StartSandboxLinux(gpu_info_, watchdog_thread_); |
| 185 #elif defined(OS_WIN) |
| 186 return StartSandboxWindows(sandbox_info_); |
| 187 #elif defined(OS_MACOSX) |
| 188 return Sandbox::SandboxIsCurrentlyActive(); |
| 189 #else |
| 190 return false; |
| 191 #endif |
| 192 } |
| 193 |
| 194 void Initialize(base::Time start_time, |
| 195 bool dead_on_arrival, |
| 196 std::vector<gpu::GpuInitLogMessage> init_log_messages, |
| 197 gpu::GpuMemoryBufferFactory* gpu_buffer_factory) override { |
| 198 base::ThreadPriority io_thread_priority = base::ThreadPriority::NORMAL; |
| 199 #if defined(OS_ANDROID) || defined(OS_CHROMEOS) |
| 200 io_thread_priority = base::ThreadPriority::DISPLAY; |
| 201 #endif |
| 202 gpu_process_.reset(new GpuProcess(io_thread_priority)); |
| 203 |
| 204 GpuChildThread* child_thread = |
| 205 new GpuChildThread(watchdog_thread_, dead_on_arrival, gpu_info_, |
| 206 std::move(init_log_messages), gpu_buffer_factory); |
| 207 child_thread->Init(start_time); |
| 208 |
| 209 gpu_process_->set_main_thread(child_thread); |
| 210 |
| 211 #if defined(OS_ANDROID) |
| 212 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
| 213 tracing::GraphicsMemoryDumpProvider::GetInstance(), "AndroidGraphics", |
| 214 nullptr); |
| 215 #endif |
| 216 } |
| 217 |
| 218 const base::CommandLine* command_line_; |
| 219 gpu::GpuWatchdogThread* watchdog_thread_ = nullptr; |
| 220 gpu::GPUInfo gpu_info_; |
| 221 std::unique_ptr<base::MessageLoop> message_loop_; |
| 222 std::unique_ptr<GpuProcess> gpu_process_; |
| 223 #if defined(OS_WIN) |
| 224 sandbox::SandboxInterfaceInfo* sandbox_info_ = nullptr; |
| 225 #endif |
| 226 |
| 227 DISALLOW_COPY_AND_ASSIGN(ContentGpuInitDelegate); |
| 228 }; |
123 | 229 |
124 } // namespace anonymous | 230 } // namespace anonymous |
125 | 231 |
126 // Main function for starting the Gpu process. | 232 // Main function for starting the Gpu process. |
127 int GpuMain(const MainFunctionParams& parameters) { | 233 int GpuMain(const MainFunctionParams& parameters) { |
128 TRACE_EVENT0("gpu", "GpuMain"); | 234 TRACE_EVENT0("gpu", "GpuMain"); |
129 base::trace_event::TraceLog::GetInstance()->SetProcessName("GPU Process"); | 235 base::trace_event::TraceLog::GetInstance()->SetProcessName("GPU Process"); |
130 base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex( | 236 base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex( |
131 kTraceEventGpuProcessSortIndex); | 237 kTraceEventGpuProcessSortIndex); |
132 | 238 |
133 const base::CommandLine& command_line = parameters.command_line; | 239 DCHECK(parameters.command_line.HasSwitch(switches::kGpuVendorID) && |
134 if (command_line.HasSwitch(switches::kGpuStartupDialog)) { | 240 parameters.command_line.HasSwitch(switches::kGpuDeviceID) && |
135 ChildProcess::WaitForDebugger("Gpu"); | 241 parameters.command_line.HasSwitch(switches::kGpuDriverVersion)); |
136 } | 242 #if defined(USE_X11) && !defined(OS_CHROMEOS) |
| 243 DCHECK(parameters.command_line.HasSwitch(switches::kWindowDepth)); |
| 244 DCHECK(parameters.command_line.HasSwitch(switches::kX11VisualID)); |
| 245 #endif // defined(USE_X11) && !defined(OS_CHROMEOS) |
137 | 246 |
138 base::Time start_time = base::Time::Now(); | 247 ContentGpuInitDelegate init_delegate(¶meters.command_line); |
139 | |
140 #if defined(OS_WIN) | 248 #if defined(OS_WIN) |
141 // Prevent Windows from displaying a modal dialog on failures like not being | 249 init_delegate.set_sandbox_info(parameters.sandbox_info); |
142 // able to load a DLL. | |
143 SetErrorMode( | |
144 SEM_FAILCRITICALERRORS | | |
145 SEM_NOGPFAULTERRORBOX | | |
146 SEM_NOOPENFILEERRORBOX); | |
147 #elif defined(USE_X11) | |
148 ui::SetDefaultX11ErrorHandlers(); | |
149 | |
150 #if !defined(OS_CHROMEOS) | |
151 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( | |
152 switches::kWindowDepth)); | |
153 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( | |
154 switches::kX11VisualID)); | |
155 #endif | 250 #endif |
156 | 251 gpu::GpuInit gpu_init(&init_delegate, parameters.command_line); |
157 #endif | |
158 | |
159 logging::SetLogMessageHandler(GpuProcessLogMessageHandler); | |
160 | |
161 if (command_line.HasSwitch(switches::kSupportsDualGpus)) { | |
162 std::string types = command_line.GetSwitchValueASCII( | |
163 switches::kGpuDriverBugWorkarounds); | |
164 std::set<int> workarounds; | |
165 gpu::StringToFeatureSet(types, &workarounds); | |
166 if (workarounds.count(gpu::FORCE_DISCRETE_GPU) == 1) | |
167 ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu(); | |
168 else if (workarounds.count(gpu::FORCE_INTEGRATED_GPU) == 1) | |
169 ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu(); | |
170 } | |
171 | |
172 // Initialization of the OpenGL bindings may fail, in which case we | |
173 // will need to tear down this process. However, we can not do so | |
174 // safely until the IPC channel is set up, because the detection of | |
175 // early return of a child process is implemented using an IPC | |
176 // channel error. If the IPC channel is not fully set up between the | |
177 // browser and GPU process, and the GPU process crashes or exits | |
178 // early, the browser process will never detect it. For this reason | |
179 // we defer tearing down the GPU process until receiving the | |
180 // GpuMsg_Initialize message from the browser. | |
181 bool dead_on_arrival = false; | |
182 | |
183 #if defined(OS_WIN) | |
184 // Use a UI message loop because ANGLE and the desktop GL platform can | |
185 // create child windows to render to. | |
186 base::MessagePumpForGpu::InitFactory(); | |
187 base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI); | |
188 #elif defined(OS_LINUX) && defined(USE_X11) | |
189 // We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX | |
190 // and https://crbug.com/326995. | |
191 base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI); | |
192 std::unique_ptr<ui::PlatformEventSource> event_source = | |
193 ui::PlatformEventSource::CreateDefault(); | |
194 #elif defined(OS_LINUX) | |
195 base::MessageLoop main_message_loop(base::MessageLoop::TYPE_DEFAULT); | |
196 #elif defined(OS_MACOSX) | |
197 // This is necessary for CoreAnimation layers hosted in the GPU process to be | |
198 // drawn. See http://crbug.com/312462. | |
199 std::unique_ptr<base::MessagePump> pump(new base::MessagePumpCFRunLoop()); | |
200 base::MessageLoop main_message_loop(std::move(pump)); | |
201 #else | |
202 base::MessageLoop main_message_loop(base::MessageLoop::TYPE_IO); | |
203 #endif | |
204 | |
205 base::PlatformThread::SetName("CrGpuMain"); | |
206 | |
207 // In addition to disabling the watchdog if the command line switch is | |
208 // present, disable the watchdog on valgrind because the code is expected | |
209 // to run slowly in that case. | |
210 bool enable_watchdog = | |
211 !command_line.HasSwitch(switches::kDisableGpuWatchdog) && | |
212 !RunningOnValgrind(); | |
213 | |
214 // Disable the watchdog in debug builds because they tend to only be run by | |
215 // developers who will not appreciate the watchdog killing the GPU process. | |
216 #ifndef NDEBUG | |
217 enable_watchdog = false; | |
218 #endif | |
219 | |
220 bool delayed_watchdog_enable = false; | |
221 | |
222 #if defined(OS_CHROMEOS) | |
223 // Don't start watchdog immediately, to allow developers to switch to VT2 on | |
224 // startup. | |
225 delayed_watchdog_enable = true; | |
226 #endif | |
227 | |
228 scoped_refptr<gpu::GpuWatchdogThread> watchdog_thread; | |
229 | |
230 // Start the GPU watchdog only after anything that is expected to be time | |
231 // consuming has completed, otherwise the process is liable to be aborted. | |
232 if (enable_watchdog && !delayed_watchdog_enable) | |
233 watchdog_thread = gpu::GpuWatchdogThread::Create(); | |
234 | |
235 // Initializes StatisticsRecorder which tracks UMA histograms. | |
236 base::StatisticsRecorder::Initialize(); | |
237 | |
238 gpu::GPUInfo gpu_info; | |
239 // Get vendor_id, device_id, driver_version from browser process through | |
240 // commandline switches. | |
241 GetGpuInfoFromCommandLine(gpu_info, command_line); | |
242 gpu_info.in_process_gpu = false; | |
243 | |
244 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) | |
245 media::VaapiWrapper::PreSandboxInitialization(); | |
246 #endif | |
247 | |
248 #if defined(OS_ANDROID) || defined(OS_CHROMEOS) | |
249 // Set thread priority before sandbox initialization. | |
250 base::PlatformThread::SetCurrentThreadPriority(base::ThreadPriority::DISPLAY); | |
251 #endif | |
252 | |
253 // Warm up resources that don't need access to GPUInfo. | |
254 WarmUpSandbox(); | |
255 | |
256 #if defined(OS_LINUX) | |
257 bool initialized_sandbox = false; | |
258 // On Chrome OS ARM Mali, GPU driver userspace creates threads when | |
259 // initializing a GL context, so start the sandbox early. | |
260 if (command_line.HasSwitch(switches::kGpuSandboxStartEarly)) { | |
261 gpu_info.sandboxed = StartSandboxLinux(gpu_info, watchdog_thread.get()); | |
262 initialized_sandbox = true; | |
263 } | |
264 #endif // defined(OS_LINUX) | |
265 | |
266 base::TimeTicks before_initialize_one_off = base::TimeTicks::Now(); | |
267 | |
268 // Determine if we need to initialize GL here or it has already been done. | |
269 bool gl_already_initialized = false; | |
270 #if defined(OS_MACOSX) | |
271 if (!command_line.HasSwitch(switches::kNoSandbox)) { | |
272 // On Mac, if the sandbox is enabled, then gl::init::InitializeGLOneOff() | |
273 // is called from the sandbox warmup code before getting here. | |
274 gl_already_initialized = true; | |
275 } | |
276 #endif | |
277 if (command_line.HasSwitch(switches::kInProcessGPU)) { | |
278 // With in-process GPU, gl::init::InitializeGLOneOff() is called from | |
279 // GpuChildThread before getting here. | |
280 gl_already_initialized = true; | |
281 } | |
282 | |
283 // Load and initialize the GL implementation and locate the GL entry points. | |
284 bool gl_initialized = | |
285 gl_already_initialized | |
286 ? gl::GetGLImplementation() != gl::kGLImplementationNone | |
287 : gl::init::InitializeGLOneOff(); | |
288 if (gl_initialized) { | |
289 // We need to collect GL strings (VENDOR, RENDERER) for blacklisting | |
290 // purposes. However, on Mac we don't actually use them. As documented in | |
291 // crbug.com/222934, due to some driver issues, glGetString could take | |
292 // multiple seconds to finish, which in turn cause the GPU process to | |
293 // crash. | |
294 // By skipping the following code on Mac, we don't really lose anything, | |
295 // because the basic GPU information is passed down from browser process | |
296 // and we already registered them through SetGpuInfo() above. | |
297 base::TimeTicks before_collect_context_graphics_info = | |
298 base::TimeTicks::Now(); | |
299 #if !defined(OS_MACOSX) | |
300 if (!CollectGraphicsInfo(gpu_info)) | |
301 dead_on_arrival = true; | |
302 | |
303 // Recompute gpu driver bug workarounds. | |
304 // This is necessary on systems where vendor_id/device_id aren't available | |
305 // (Chrome OS, Android) or where workarounds may be dependent on GL_VENDOR | |
306 // and GL_RENDERER strings which are lazily computed (Linux). | |
307 if (!command_line.HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) { | |
308 // TODO: this can not affect disabled extensions, since they're already | |
309 // initialized in the bindings. This should be moved before bindings | |
310 // initialization. However, populating GPUInfo fully works only on | |
311 // Android. Other platforms would need the bindings to query GL strings. | |
312 gpu::ApplyGpuDriverBugWorkarounds( | |
313 gpu_info, const_cast<base::CommandLine*>(&command_line)); | |
314 } | |
315 #endif // !defined(OS_MACOSX) | |
316 | |
317 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
318 if (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA | |
319 gpu_info.driver_vendor == "NVIDIA" && !CanAccessNvidiaDeviceFile()) | |
320 dead_on_arrival = true; | |
321 #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
322 | |
323 base::TimeDelta collect_context_time = | |
324 base::TimeTicks::Now() - before_collect_context_graphics_info; | |
325 UMA_HISTOGRAM_TIMES("GPU.CollectContextGraphicsInfo", collect_context_time); | |
326 } else { // gl_initialized | |
327 VLOG(1) << "gl::init::InitializeGLOneOff failed"; | |
328 dead_on_arrival = true; | |
329 } | |
330 | |
331 base::TimeDelta initialize_one_off_time = | |
332 base::TimeTicks::Now() - before_initialize_one_off; | |
333 UMA_HISTOGRAM_MEDIUM_TIMES("GPU.InitializeOneOffMediumTime", | |
334 initialize_one_off_time); | |
335 if (enable_watchdog && delayed_watchdog_enable) | |
336 watchdog_thread = gpu::GpuWatchdogThread::Create(); | |
337 | |
338 // OSMesa is expected to run very slowly, so disable the watchdog in that | |
339 // case. | |
340 if (enable_watchdog && | |
341 gl::GetGLImplementation() == gl::kGLImplementationOSMesaGL) { | |
342 watchdog_thread->Stop(); | |
343 watchdog_thread = NULL; | |
344 } | |
345 | |
346 #if defined(OS_LINUX) | |
347 if (!initialized_sandbox) | |
348 gpu_info.sandboxed = StartSandboxLinux(gpu_info, watchdog_thread.get()); | |
349 #elif defined(OS_WIN) | |
350 gpu_info.sandboxed = StartSandboxWindows(parameters.sandbox_info); | |
351 #elif defined(OS_MACOSX) | |
352 gpu_info.sandboxed = Sandbox::SandboxIsCurrentlyActive(); | |
353 #endif | |
354 | |
355 logging::SetLogMessageHandler(NULL); | |
356 | |
357 std::unique_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory; | |
358 if (gpu::GetNativeGpuMemoryBufferType() != gfx::EMPTY_BUFFER) | |
359 gpu_memory_buffer_factory = gpu::GpuMemoryBufferFactory::CreateNativeType(); | |
360 | |
361 base::ThreadPriority io_thread_priority = base::ThreadPriority::NORMAL; | |
362 #if defined(OS_ANDROID) || defined(OS_CHROMEOS) | |
363 io_thread_priority = base::ThreadPriority::DISPLAY; | |
364 #endif | |
365 | |
366 GpuProcess gpu_process(io_thread_priority); | |
367 | |
368 GpuChildThread* child_thread = new GpuChildThread( | |
369 watchdog_thread.get(), dead_on_arrival, gpu_info, deferred_messages.Get(), | |
370 gpu_memory_buffer_factory.get()); | |
371 while (!deferred_messages.Get().empty()) | |
372 deferred_messages.Get().pop(); | |
373 | |
374 child_thread->Init(start_time); | |
375 | |
376 gpu_process.set_main_thread(child_thread); | |
377 | |
378 if (watchdog_thread.get()) | |
379 watchdog_thread->AddPowerObserver(); | |
380 | |
381 #if defined(OS_ANDROID) | |
382 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( | |
383 tracing::GraphicsMemoryDumpProvider::GetInstance(), "AndroidGraphics", | |
384 nullptr); | |
385 #endif | |
386 | |
387 { | 252 { |
388 TRACE_EVENT0("gpu", "Run Message Loop"); | 253 TRACE_EVENT0("gpu", "Run Message Loop"); |
389 base::RunLoop().Run(); | 254 base::RunLoop().Run(); |
390 } | 255 } |
391 | 256 |
392 child_thread->StopWatchdog(); | 257 return 0; |
393 | |
394 return dead_on_arrival ? 2 : 0; | |
395 } | 258 } |
396 | 259 |
397 namespace { | 260 namespace { |
398 | 261 |
399 void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info, | |
400 const base::CommandLine& command_line) { | |
401 DCHECK(command_line.HasSwitch(switches::kGpuVendorID) && | |
402 command_line.HasSwitch(switches::kGpuDeviceID) && | |
403 command_line.HasSwitch(switches::kGpuDriverVersion)); | |
404 bool success = base::HexStringToUInt( | |
405 command_line.GetSwitchValueASCII(switches::kGpuVendorID), | |
406 &gpu_info.gpu.vendor_id); | |
407 DCHECK(success); | |
408 success = base::HexStringToUInt( | |
409 command_line.GetSwitchValueASCII(switches::kGpuDeviceID), | |
410 &gpu_info.gpu.device_id); | |
411 DCHECK(success); | |
412 gpu_info.driver_vendor = | |
413 command_line.GetSwitchValueASCII(switches::kGpuDriverVendor); | |
414 gpu_info.driver_version = | |
415 command_line.GetSwitchValueASCII(switches::kGpuDriverVersion); | |
416 gpu_info.driver_date = | |
417 command_line.GetSwitchValueASCII(switches::kGpuDriverDate); | |
418 gpu::ParseSecondaryGpuDevicesFromCommandLine(command_line, &gpu_info); | |
419 | |
420 // Set active gpu device. | |
421 if (command_line.HasSwitch(switches::kGpuActiveVendorID) && | |
422 command_line.HasSwitch(switches::kGpuActiveDeviceID)) { | |
423 uint32_t active_vendor_id = 0; | |
424 uint32_t active_device_id = 0; | |
425 success = base::HexStringToUInt( | |
426 command_line.GetSwitchValueASCII(switches::kGpuActiveVendorID), | |
427 &active_vendor_id); | |
428 DCHECK(success); | |
429 success = base::HexStringToUInt( | |
430 command_line.GetSwitchValueASCII(switches::kGpuActiveDeviceID), | |
431 &active_device_id); | |
432 DCHECK(success); | |
433 if (gpu_info.gpu.vendor_id == active_vendor_id && | |
434 gpu_info.gpu.device_id == active_device_id) { | |
435 gpu_info.gpu.active = true; | |
436 } else { | |
437 for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) { | |
438 if (gpu_info.secondary_gpus[i].vendor_id == active_vendor_id && | |
439 gpu_info.secondary_gpus[i].device_id == active_device_id) { | |
440 gpu_info.secondary_gpus[i].active = true; | |
441 break; | |
442 } | |
443 } | |
444 } | |
445 } | |
446 | |
447 GetContentClient()->SetGpuInfo(gpu_info); | |
448 } | |
449 | |
450 void WarmUpSandbox() { | |
451 { | |
452 TRACE_EVENT0("gpu", "Warm up rand"); | |
453 // Warm up the random subsystem, which needs to be done pre-sandbox on all | |
454 // platforms. | |
455 (void) base::RandUint64(); | |
456 } | |
457 | |
458 #if defined(OS_WIN) | |
459 media::DXVAVideoDecodeAccelerator::PreSandboxInitialization(); | |
460 media::MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization(); | |
461 #endif | |
462 } | |
463 | |
464 #if !defined(OS_MACOSX) | |
465 bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info) { | |
466 TRACE_EVENT0("gpu,startup", "Collect Graphics Info"); | |
467 | |
468 bool res = true; | |
469 gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(&gpu_info); | |
470 switch (result) { | |
471 case gpu::kCollectInfoFatalFailure: | |
472 LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal)."; | |
473 res = false; | |
474 break; | |
475 case gpu::kCollectInfoNonFatalFailure: | |
476 DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal)."; | |
477 break; | |
478 case gpu::kCollectInfoNone: | |
479 NOTREACHED(); | |
480 break; | |
481 case gpu::kCollectInfoSuccess: | |
482 break; | |
483 } | |
484 GetContentClient()->SetGpuInfo(gpu_info); | |
485 return res; | |
486 } | |
487 #endif | |
488 | |
489 #if defined(OS_LINUX) | 262 #if defined(OS_LINUX) |
490 #if !defined(OS_CHROMEOS) | |
491 bool CanAccessNvidiaDeviceFile() { | |
492 bool res = true; | |
493 base::ThreadRestrictions::AssertIOAllowed(); | |
494 if (access("/dev/nvidiactl", R_OK) != 0) { | |
495 DVLOG(1) << "NVIDIA device file /dev/nvidiactl access denied"; | |
496 res = false; | |
497 } | |
498 return res; | |
499 } | |
500 #endif | |
501 | |
502 bool StartSandboxLinux(const gpu::GPUInfo& gpu_info, | 263 bool StartSandboxLinux(const gpu::GPUInfo& gpu_info, |
503 gpu::GpuWatchdogThread* watchdog_thread) { | 264 gpu::GpuWatchdogThread* watchdog_thread) { |
504 TRACE_EVENT0("gpu,startup", "Initialize sandbox"); | 265 TRACE_EVENT0("gpu,startup", "Initialize sandbox"); |
505 | 266 |
506 bool res = false; | 267 bool res = false; |
507 | 268 |
508 if (watchdog_thread) { | 269 if (watchdog_thread) { |
509 // LinuxSandbox needs to be able to ensure that the thread | 270 // LinuxSandbox needs to be able to ensure that the thread |
510 // has really been stopped. | 271 // has really been stopped. |
511 LinuxSandbox::StopThread(watchdog_thread); | 272 LinuxSandbox::StopThread(watchdog_thread); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 return true; | 308 return true; |
548 } | 309 } |
549 | 310 |
550 return false; | 311 return false; |
551 } | 312 } |
552 #endif // defined(OS_WIN) | 313 #endif // defined(OS_WIN) |
553 | 314 |
554 } // namespace. | 315 } // namespace. |
555 | 316 |
556 } // namespace content | 317 } // namespace content |
OLD | NEW |