| 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 <stdlib.h> | 5 #include <stdlib.h> |
| 6 | 6 |
| 7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
| 8 #include <dwmapi.h> | 8 #include <dwmapi.h> |
| 9 #include <windows.h> | 9 #include <windows.h> |
| 10 #endif | 10 #endif |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 #if defined(ADDRESS_SANITIZER) | 59 #if defined(ADDRESS_SANITIZER) |
| 60 #include <sanitizer/asan_interface.h> | 60 #include <sanitizer/asan_interface.h> |
| 61 #endif | 61 #endif |
| 62 | 62 |
| 63 const int kGpuTimeout = 10000; | 63 const int kGpuTimeout = 10000; |
| 64 | 64 |
| 65 namespace content { | 65 namespace content { |
| 66 | 66 |
| 67 namespace { | 67 namespace { |
| 68 | 68 |
| 69 void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info, |
| 70 const CommandLine& command_line); |
| 69 bool WarmUpSandbox(const CommandLine& command_line); | 71 bool WarmUpSandbox(const CommandLine& command_line); |
| 72 |
| 73 #if !defined(OS_MACOSX) |
| 74 bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info); |
| 75 #endif |
| 76 |
| 70 #if defined(OS_LINUX) | 77 #if defined(OS_LINUX) |
| 78 #if !defined(OS_CHROMEOS) |
| 79 bool CanAccessNvidiaDeviceFile(); |
| 80 #endif |
| 71 bool StartSandboxLinux(const gpu::GPUInfo&, GpuWatchdogThread*, bool); | 81 bool StartSandboxLinux(const gpu::GPUInfo&, GpuWatchdogThread*, bool); |
| 72 #elif defined(OS_WIN) | 82 #elif defined(OS_WIN) |
| 73 bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo*); | 83 bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo*); |
| 74 #endif | 84 #endif |
| 75 | 85 |
| 76 base::LazyInstance<GpuChildThread::DeferredMessages> deferred_messages = | 86 base::LazyInstance<GpuChildThread::DeferredMessages> deferred_messages = |
| 77 LAZY_INSTANCE_INITIALIZER; | 87 LAZY_INSTANCE_INITIALIZER; |
| 78 | 88 |
| 79 bool GpuProcessLogMessageHandler(int severity, | 89 bool GpuProcessLogMessageHandler(int severity, |
| 80 const char* file, int line, | 90 const char* file, int line, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 // Start the GPU watchdog only after anything that is expected to be time | 204 // Start the GPU watchdog only after anything that is expected to be time |
| 195 // consuming has completed, otherwise the process is liable to be aborted. | 205 // consuming has completed, otherwise the process is liable to be aborted. |
| 196 if (enable_watchdog && !delayed_watchdog_enable) { | 206 if (enable_watchdog && !delayed_watchdog_enable) { |
| 197 watchdog_thread = new GpuWatchdogThread(kGpuTimeout); | 207 watchdog_thread = new GpuWatchdogThread(kGpuTimeout); |
| 198 watchdog_thread->Start(); | 208 watchdog_thread->Start(); |
| 199 } | 209 } |
| 200 | 210 |
| 201 gpu::GPUInfo gpu_info; | 211 gpu::GPUInfo gpu_info; |
| 202 // Get vendor_id, device_id, driver_version from browser process through | 212 // Get vendor_id, device_id, driver_version from browser process through |
| 203 // commandline switches. | 213 // commandline switches. |
| 204 DCHECK(command_line.HasSwitch(switches::kGpuVendorID) && | 214 GetGpuInfoFromCommandLine(gpu_info, command_line); |
| 205 command_line.HasSwitch(switches::kGpuDeviceID) && | |
| 206 command_line.HasSwitch(switches::kGpuDriverVersion)); | |
| 207 bool success = base::HexStringToUInt( | |
| 208 command_line.GetSwitchValueASCII(switches::kGpuVendorID), | |
| 209 &gpu_info.gpu.vendor_id); | |
| 210 DCHECK(success); | |
| 211 success = base::HexStringToUInt( | |
| 212 command_line.GetSwitchValueASCII(switches::kGpuDeviceID), | |
| 213 &gpu_info.gpu.device_id); | |
| 214 DCHECK(success); | |
| 215 gpu_info.driver_vendor = | |
| 216 command_line.GetSwitchValueASCII(switches::kGpuDriverVendor); | |
| 217 gpu_info.driver_version = | |
| 218 command_line.GetSwitchValueASCII(switches::kGpuDriverVersion); | |
| 219 GetContentClient()->SetGpuInfo(gpu_info); | |
| 220 | 215 |
| 221 base::TimeDelta collect_context_time; | 216 base::TimeDelta collect_context_time; |
| 222 base::TimeDelta initialize_one_off_time; | 217 base::TimeDelta initialize_one_off_time; |
| 223 | 218 |
| 224 // Warm up resources that don't need access to GPUInfo. | 219 // Warm up resources that don't need access to GPUInfo. |
| 225 if (WarmUpSandbox(command_line)) { | 220 if (WarmUpSandbox(command_line)) { |
| 226 #if defined(OS_LINUX) | 221 #if defined(OS_LINUX) |
| 227 bool initialized_sandbox = false; | 222 bool initialized_sandbox = false; |
| 228 bool initialized_gl_context = false; | 223 bool initialized_gl_context = false; |
| 229 bool should_initialize_gl_context = false; | 224 bool should_initialize_gl_context = false; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 // purposes. However, on Mac we don't actually use them. As documented in | 261 // purposes. However, on Mac we don't actually use them. As documented in |
| 267 // crbug.com/222934, due to some driver issues, glGetString could take | 262 // crbug.com/222934, due to some driver issues, glGetString could take |
| 268 // multiple seconds to finish, which in turn cause the GPU process to | 263 // multiple seconds to finish, which in turn cause the GPU process to |
| 269 // crash. | 264 // crash. |
| 270 // By skipping the following code on Mac, we don't really lose anything, | 265 // By skipping the following code on Mac, we don't really lose anything, |
| 271 // because the basic GPU information is passed down from browser process | 266 // because the basic GPU information is passed down from browser process |
| 272 // and we already registered them through SetGpuInfo() above. | 267 // and we already registered them through SetGpuInfo() above. |
| 273 base::TimeTicks before_collect_context_graphics_info = | 268 base::TimeTicks before_collect_context_graphics_info = |
| 274 base::TimeTicks::Now(); | 269 base::TimeTicks::Now(); |
| 275 #if !defined(OS_MACOSX) | 270 #if !defined(OS_MACOSX) |
| 276 gpu::CollectInfoResult result = | 271 if (!CollectGraphicsInfo(gpu_info)) |
| 277 gpu::CollectContextGraphicsInfo(&gpu_info); | 272 dead_on_arrival = true; |
| 278 switch (result) { | |
| 279 case gpu::kCollectInfoFatalFailure: | |
| 280 LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal)."; | |
| 281 dead_on_arrival = true; | |
| 282 break; | |
| 283 case gpu::kCollectInfoNonFatalFailure: | |
| 284 VLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal)."; | |
| 285 break; | |
| 286 case gpu::kCollectInfoSuccess: | |
| 287 break; | |
| 288 } | |
| 289 GetContentClient()->SetGpuInfo(gpu_info); | |
| 290 | 273 |
| 291 #if defined(OS_CHROMEOS) || defined(OS_ANDROID) | 274 #if defined(OS_CHROMEOS) || defined(OS_ANDROID) |
| 292 // Recompute gpu driver bug workarounds - this is specifically useful | 275 // Recompute gpu driver bug workarounds - this is specifically useful |
| 293 // on systems where vendor_id/device_id aren't available. | 276 // on systems where vendor_id/device_id aren't available. |
| 294 if (!command_line.HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) { | 277 if (!command_line.HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) { |
| 295 gpu::ApplyGpuDriverBugWorkarounds( | 278 gpu::ApplyGpuDriverBugWorkarounds( |
| 296 gpu_info, const_cast<CommandLine*>(&command_line)); | 279 gpu_info, const_cast<CommandLine*>(&command_line)); |
| 297 } | 280 } |
| 298 #endif | 281 #endif |
| 299 | 282 |
| 300 #if defined(OS_LINUX) | 283 #if defined(OS_LINUX) |
| 301 initialized_gl_context = true; | 284 initialized_gl_context = true; |
| 302 #if !defined(OS_CHROMEOS) | 285 #if !defined(OS_CHROMEOS) |
| 303 if (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA | 286 if (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA |
| 304 gpu_info.driver_vendor == "NVIDIA") { | 287 gpu_info.driver_vendor == "NVIDIA" && |
| 305 base::ThreadRestrictions::AssertIOAllowed(); | 288 !CanAccessNvidiaDeviceFile()) |
| 306 if (access("/dev/nvidiactl", R_OK) != 0) { | 289 dead_on_arrival = true; |
| 307 VLOG(1) << "NVIDIA device file /dev/nvidiactl access denied"; | |
| 308 dead_on_arrival = true; | |
| 309 } | |
| 310 } | |
| 311 #endif // !defined(OS_CHROMEOS) | 290 #endif // !defined(OS_CHROMEOS) |
| 312 #endif // defined(OS_LINUX) | 291 #endif // defined(OS_LINUX) |
| 313 #endif // !defined(OS_MACOSX) | 292 #endif // !defined(OS_MACOSX) |
| 314 collect_context_time = | 293 collect_context_time = |
| 315 base::TimeTicks::Now() - before_collect_context_graphics_info; | 294 base::TimeTicks::Now() - before_collect_context_graphics_info; |
| 316 } else { | 295 } else { // gl_initialized |
| 317 VLOG(1) << "gfx::GLSurface::InitializeOneOff failed"; | 296 VLOG(1) << "gfx::GLSurface::InitializeOneOff failed"; |
| 318 dead_on_arrival = true; | 297 dead_on_arrival = true; |
| 319 } | 298 } |
| 320 | 299 |
| 321 initialize_one_off_time = | 300 initialize_one_off_time = |
| 322 base::TimeTicks::Now() - before_initialize_one_off; | 301 base::TimeTicks::Now() - before_initialize_one_off; |
| 323 | 302 |
| 324 if (enable_watchdog && delayed_watchdog_enable) { | 303 if (enable_watchdog && delayed_watchdog_enable) { |
| 325 watchdog_thread = new GpuWatchdogThread(kGpuTimeout); | 304 watchdog_thread = new GpuWatchdogThread(kGpuTimeout); |
| 326 watchdog_thread->Start(); | 305 watchdog_thread->Start(); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 main_message_loop.Run(); | 356 main_message_loop.Run(); |
| 378 } | 357 } |
| 379 | 358 |
| 380 child_thread->StopWatchdog(); | 359 child_thread->StopWatchdog(); |
| 381 | 360 |
| 382 return 0; | 361 return 0; |
| 383 } | 362 } |
| 384 | 363 |
| 385 namespace { | 364 namespace { |
| 386 | 365 |
| 366 void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info, |
| 367 const CommandLine& command_line) { |
| 368 DCHECK(command_line.HasSwitch(switches::kGpuVendorID) && |
| 369 command_line.HasSwitch(switches::kGpuDeviceID) && |
| 370 command_line.HasSwitch(switches::kGpuDriverVersion)); |
| 371 bool success = base::HexStringToUInt( |
| 372 command_line.GetSwitchValueASCII(switches::kGpuVendorID), |
| 373 &gpu_info.gpu.vendor_id); |
| 374 DCHECK(success); |
| 375 success = base::HexStringToUInt( |
| 376 command_line.GetSwitchValueASCII(switches::kGpuDeviceID), |
| 377 &gpu_info.gpu.device_id); |
| 378 DCHECK(success); |
| 379 gpu_info.driver_vendor = |
| 380 command_line.GetSwitchValueASCII(switches::kGpuDriverVendor); |
| 381 gpu_info.driver_version = |
| 382 command_line.GetSwitchValueASCII(switches::kGpuDriverVersion); |
| 383 GetContentClient()->SetGpuInfo(gpu_info); |
| 384 } |
| 385 |
| 386 bool WarmUpSandbox(const CommandLine& command_line) { |
| 387 { |
| 388 TRACE_EVENT0("gpu", "Warm up rand"); |
| 389 // Warm up the random subsystem, which needs to be done pre-sandbox on all |
| 390 // platforms. |
| 391 (void) base::RandUint64(); |
| 392 } |
| 393 return true; |
| 394 } |
| 395 |
| 396 #if !defined(OS_MACOSX) |
| 397 bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info) { |
| 398 bool res = true; |
| 399 gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(&gpu_info); |
| 400 switch (result) { |
| 401 case gpu::kCollectInfoFatalFailure: |
| 402 LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal)."; |
| 403 res = false; |
| 404 break; |
| 405 case gpu::kCollectInfoNonFatalFailure: |
| 406 VLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal)."; |
| 407 break; |
| 408 case gpu::kCollectInfoSuccess: |
| 409 break; |
| 410 } |
| 411 GetContentClient()->SetGpuInfo(gpu_info); |
| 412 return res; |
| 413 } |
| 414 #endif |
| 415 |
| 387 #if defined(OS_LINUX) | 416 #if defined(OS_LINUX) |
| 417 #if !defined(OS_CHROMEOS) |
| 418 bool CanAccessNvidiaDeviceFile() { |
| 419 bool res = true; |
| 420 base::ThreadRestrictions::AssertIOAllowed(); |
| 421 if (access("/dev/nvidiactl", R_OK) != 0) { |
| 422 VLOG(1) << "NVIDIA device file /dev/nvidiactl access denied"; |
| 423 res = false; |
| 424 } |
| 425 return res; |
| 426 } |
| 427 #endif |
| 428 |
| 388 void CreateDummyGlContext() { | 429 void CreateDummyGlContext() { |
| 389 scoped_refptr<gfx::GLSurface> surface( | 430 scoped_refptr<gfx::GLSurface> surface( |
| 390 gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size())); | 431 gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size())); |
| 391 if (!surface.get()) { | 432 if (!surface.get()) { |
| 392 VLOG(1) << "gfx::GLSurface::CreateOffscreenGLSurface failed"; | 433 VLOG(1) << "gfx::GLSurface::CreateOffscreenGLSurface failed"; |
| 393 return; | 434 return; |
| 394 } | 435 } |
| 395 | 436 |
| 396 // On Linux, this is needed to make sure /dev/nvidiactl has | 437 // On Linux, this is needed to make sure /dev/nvidiactl has |
| 397 // been opened and its descriptor cached. | 438 // been opened and its descriptor cached. |
| 398 scoped_refptr<gfx::GLContext> context(gfx::GLContext::CreateGLContext( | 439 scoped_refptr<gfx::GLContext> context(gfx::GLContext::CreateGLContext( |
| 399 NULL, surface.get(), gfx::PreferDiscreteGpu)); | 440 NULL, surface.get(), gfx::PreferDiscreteGpu)); |
| 400 if (!context.get()) { | 441 if (!context.get()) { |
| 401 VLOG(1) << "gfx::GLContext::CreateGLContext failed"; | 442 VLOG(1) << "gfx::GLContext::CreateGLContext failed"; |
| 402 return; | 443 return; |
| 403 } | 444 } |
| 404 | 445 |
| 405 // Similarly, this is needed for /dev/nvidia0. | 446 // Similarly, this is needed for /dev/nvidia0. |
| 406 if (context->MakeCurrent(surface.get())) { | 447 if (context->MakeCurrent(surface.get())) { |
| 407 context->ReleaseCurrent(surface.get()); | 448 context->ReleaseCurrent(surface.get()); |
| 408 } else { | 449 } else { |
| 409 VLOG(1) << "gfx::GLContext::MakeCurrent failed"; | 450 VLOG(1) << "gfx::GLContext::MakeCurrent failed"; |
| 410 } | 451 } |
| 411 } | 452 } |
| 412 #endif | |
| 413 | 453 |
| 414 bool WarmUpSandbox(const CommandLine& command_line) { | |
| 415 { | |
| 416 TRACE_EVENT0("gpu", "Warm up rand"); | |
| 417 // Warm up the random subsystem, which needs to be done pre-sandbox on all | |
| 418 // platforms. | |
| 419 (void) base::RandUint64(); | |
| 420 } | |
| 421 return true; | |
| 422 } | |
| 423 | |
| 424 #if defined(OS_LINUX) | |
| 425 void WarmUpSandboxNvidia(const gpu::GPUInfo& gpu_info, | 454 void WarmUpSandboxNvidia(const gpu::GPUInfo& gpu_info, |
| 426 bool should_initialize_gl_context) { | 455 bool should_initialize_gl_context) { |
| 427 // We special case Optimus since the vendor_id we see may not be Nvidia. | 456 // We special case Optimus since the vendor_id we see may not be Nvidia. |
| 428 bool uses_nvidia_driver = (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA. | 457 bool uses_nvidia_driver = (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA. |
| 429 gpu_info.driver_vendor == "NVIDIA") || | 458 gpu_info.driver_vendor == "NVIDIA") || |
| 430 gpu_info.optimus; | 459 gpu_info.optimus; |
| 431 if (uses_nvidia_driver && should_initialize_gl_context) { | 460 if (uses_nvidia_driver && should_initialize_gl_context) { |
| 432 // We need this on Nvidia to pre-open /dev/nvidiactl and /dev/nvidia0. | 461 // We need this on Nvidia to pre-open /dev/nvidiactl and /dev/nvidia0. |
| 433 CreateDummyGlContext(); | 462 CreateDummyGlContext(); |
| 434 } | 463 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 return true; | 512 return true; |
| 484 } | 513 } |
| 485 | 514 |
| 486 return false; | 515 return false; |
| 487 } | 516 } |
| 488 #endif // defined(OS_WIN) | 517 #endif // defined(OS_WIN) |
| 489 | 518 |
| 490 } // namespace. | 519 } // namespace. |
| 491 | 520 |
| 492 } // namespace content | 521 } // namespace content |
| OLD | NEW |