Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Unified Diff: gpu/ipc/service/gpu_init.cc

Issue 2322123002: gpu: Introduce GpuInit. (Closed)
Patch Set: . Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: gpu/ipc/service/gpu_init.cc
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
new file mode 100644
index 0000000000000000000000000000000000000000..55ff2cb6df5eaf4243b47bd0c63e60c708c58ff0
--- /dev/null
+++ b/gpu/ipc/service/gpu_init.cc
@@ -0,0 +1,260 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/ipc/service/gpu_init.h"
+
+#include "base/command_line.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/trace_event/trace_event.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/config/gpu_driver_bug_list.h"
+#include "gpu/config/gpu_info_collector.h"
+#include "gpu/config/gpu_switches.h"
+#include "gpu/config/gpu_util.h"
+#include "gpu/ipc/service/gpu_watchdog_thread.h"
+#include "gpu/ipc/service/switches.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_switches.h"
+#include "ui/gl/init/gl_factory.h"
+
+namespace gpu {
+
+namespace {
+
+void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info,
+ const base::CommandLine& command_line) {
+ if (!command_line.HasSwitch(switches::kGpuVendorID) ||
+ !command_line.HasSwitch(switches::kGpuDeviceID) ||
+ !command_line.HasSwitch(switches::kGpuDriverVersion))
+ return;
+ bool success = base::HexStringToUInt(
+ command_line.GetSwitchValueASCII(switches::kGpuVendorID),
+ &gpu_info.gpu.vendor_id);
+ DCHECK(success);
+ success = base::HexStringToUInt(
+ command_line.GetSwitchValueASCII(switches::kGpuDeviceID),
+ &gpu_info.gpu.device_id);
+ DCHECK(success);
+ gpu_info.driver_vendor =
+ command_line.GetSwitchValueASCII(switches::kGpuDriverVendor);
+ gpu_info.driver_version =
+ command_line.GetSwitchValueASCII(switches::kGpuDriverVersion);
+ gpu_info.driver_date =
+ command_line.GetSwitchValueASCII(switches::kGpuDriverDate);
+ gpu::ParseSecondaryGpuDevicesFromCommandLine(command_line, &gpu_info);
+
+ // Set active gpu device.
+ if (command_line.HasSwitch(switches::kGpuActiveVendorID) &&
+ command_line.HasSwitch(switches::kGpuActiveDeviceID)) {
+ uint32_t active_vendor_id = 0;
+ uint32_t active_device_id = 0;
+ success = base::HexStringToUInt(
+ command_line.GetSwitchValueASCII(switches::kGpuActiveVendorID),
+ &active_vendor_id);
+ DCHECK(success);
+ success = base::HexStringToUInt(
+ command_line.GetSwitchValueASCII(switches::kGpuActiveDeviceID),
+ &active_device_id);
+ DCHECK(success);
+ if (gpu_info.gpu.vendor_id == active_vendor_id &&
+ gpu_info.gpu.device_id == active_device_id) {
+ gpu_info.gpu.active = true;
+ } else {
+ for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) {
+ if (gpu_info.secondary_gpus[i].vendor_id == active_vendor_id &&
+ gpu_info.secondary_gpus[i].device_id == active_device_id) {
+ gpu_info.secondary_gpus[i].active = true;
+ break;
+ }
+ }
+ }
+ }
+}
+
+#if !defined(OS_MACOSX)
+void CollectGraphicsInfo(gpu::GPUInfo& gpu_info) {
+ TRACE_EVENT0("gpu,startup", "Collect Graphics Info");
+
+ gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(&gpu_info);
+ switch (result) {
+ case gpu::kCollectInfoFatalFailure:
+ LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
+ break;
+ case gpu::kCollectInfoNonFatalFailure:
+ DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
+ break;
+ case gpu::kCollectInfoNone:
+ NOTREACHED();
+ break;
+ case gpu::kCollectInfoSuccess:
+ break;
+ }
+}
+#endif // defined(OS_MACOSX)
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+bool CanAccessNvidiaDeviceFile() {
+ bool res = true;
+ base::ThreadRestrictions::AssertIOAllowed();
+ if (access("/dev/nvidiactl", R_OK) != 0) {
+ DVLOG(1) << "NVIDIA device file /dev/nvidiactl access denied";
+ res = false;
+ }
+ return res;
+}
+#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
+
+} // namespace
+
+GpuInit::GpuInit() {}
+
+GpuInit::~GpuInit() {}
+
+void GpuInit::InitializeAndStartSandbox(const base::CommandLine& command_line) {
+ if (command_line.HasSwitch(switches::kSupportsDualGpus)) {
+ std::set<int> workarounds;
+ gpu::GpuDriverBugList::AppendWorkaroundsFromCommandLine(&workarounds,
+ command_line);
+ gpu::InitializeDualGpusIfSupported(workarounds);
+ }
+
+ // In addition to disabling the watchdog if the command line switch is
+ // present, disable the watchdog on valgrind because the code is expected
+ // to run slowly in that case.
+ bool enable_watchdog =
+ !command_line.HasSwitch(switches::kDisableGpuWatchdog) &&
+ !RunningOnValgrind();
+
+ // Disable the watchdog in debug builds because they tend to only be run by
+ // developers who will not appreciate the watchdog killing the GPU process.
+#ifndef NDEBUG
+ enable_watchdog = false;
+#endif
+
+ bool delayed_watchdog_enable = false;
+
+#if defined(OS_CHROMEOS)
+ // Don't start watchdog immediately, to allow developers to switch to VT2 on
+ // startup.
+ delayed_watchdog_enable = true;
+#endif
+
+ // Start the GPU watchdog only after anything that is expected to be time
+ // consuming has completed, otherwise the process is liable to be aborted.
+ if (enable_watchdog && !delayed_watchdog_enable)
+ watchdog_thread_ = gpu::GpuWatchdogThread::Create();
+
+ // Get vendor_id, device_id, driver_version from browser process through
+ // commandline switches.
+ GetGpuInfoFromCommandLine(gpu_info_, command_line);
+ gpu_info_.in_process_gpu = false;
+
+ sandbox_helper_->PreSandboxStartup();
+
+#if defined(OS_LINUX)
+ // On Chrome OS ARM Mali, GPU driver userspace creates threads when
+ // initializing a GL context, so start the sandbox early.
+ if (command_line.HasSwitch(switches::kGpuSandboxStartEarly))
+ gpu_info_.sandboxed = sandbox_helper_->EnsureSandboxInitialized();
+#endif // defined(OS_LINUX)
+
+ base::TimeTicks before_initialize_one_off = base::TimeTicks::Now();
+
+ // Initialization of the OpenGL bindings may fail, in which case we
+ // will need to tear down this process. However, we can not do so
+ // safely until the IPC channel is set up, because the detection of
+ // early return of a child process is implemented using an IPC
+ // channel error. If the IPC channel is not fully set up between the
+ // browser and GPU process, and the GPU process crashes or exits
+ // early, the browser process will never detect it. For this reason
+ // we defer tearing down the GPU process until receiving the
+ // GpuMsg_Initialize message from the browser.
+
+ // Load and initialize the GL implementation and locate the GL entry points
+ // if needed. This initialization may have already happened if running in
+ // the browser process, for example.
+ bool gl_initialized = gl::GetGLImplementation() != gl::kGLImplementationNone;
+ if (!gl_initialized)
+ gl_initialized = gl::init::InitializeGLOneOff();
+
+ if (gl_initialized) {
+ // We need to collect GL strings (VENDOR, RENDERER) for blacklisting
+ // purposes. However, on Mac we don't actually use them. As documented in
+ // crbug.com/222934, due to some driver issues, glGetString could take
+ // multiple seconds to finish, which in turn cause the GPU process to
+ // crash.
+ // By skipping the following code on Mac, we don't really lose anything,
+ // because the basic GPU information is passed down from browser process
+ // and we already registered them through SetGpuInfo() above.
+ base::TimeTicks before_collect_context_graphics_info =
+ base::TimeTicks::Now();
+#if !defined(OS_MACOSX)
+ CollectGraphicsInfo(gpu_info_);
+
+ // Recompute gpu driver bug workarounds.
+ // This is necessary on systems where vendor_id/device_id aren't available
+ // (Chrome OS, Android) or where workarounds may be dependent on GL_VENDOR
+ // and GL_RENDERER strings which are lazily computed (Linux).
+ if (!command_line.HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
+ // TODO: this can not affect disabled extensions, since they're already
+ // initialized in the bindings. This should be moved before bindings
+ // initialization. However, populating GPUInfo fully works only on
+ // Android. Other platforms would need the bindings to query GL strings.
+ gpu::ApplyGpuDriverBugWorkarounds(
+ gpu_info_, const_cast<base::CommandLine*>(&command_line));
+ }
+#endif // !defined(OS_MACOSX)
+
+ base::TimeDelta collect_context_time =
+ base::TimeTicks::Now() - before_collect_context_graphics_info;
+ UMA_HISTOGRAM_TIMES("GPU.CollectContextGraphicsInfo", collect_context_time);
+ } else { // gl_initialized
+ VLOG(1) << "gl::init::InitializeGLOneOff failed";
+ }
+
+ base::TimeDelta initialize_one_off_time =
+ base::TimeTicks::Now() - before_initialize_one_off;
+ UMA_HISTOGRAM_MEDIUM_TIMES("GPU.InitializeOneOffMediumTime",
+ initialize_one_off_time);
+ if (enable_watchdog && delayed_watchdog_enable)
+ watchdog_thread_ = gpu::GpuWatchdogThread::Create();
+
+ // OSMesa is expected to run very slowly, so disable the watchdog in that
+ // case.
+ if (enable_watchdog &&
+ gl::GetGLImplementation() == gl::kGLImplementationOSMesaGL) {
+ watchdog_thread_->Stop();
+ watchdog_thread_ = NULL;
+ }
+
+ // It is necessary to make the DOA decision before entering the sandbox
+ // (because on Linux, it can attempt to access a file).
+ dead_on_arrival_ = IsDeadOnArrival();
piman 2016/09/09 03:32:41 How about returning a "success" bool from this fun
sadrul 2016/09/09 15:38:04 Thanks! That makes it much simpler. Moved all of c
+
+ if (!gpu_info_.sandboxed)
+ gpu_info_.sandboxed = sandbox_helper_->EnsureSandboxInitialized();
+}
+
+bool GpuInit::IsDeadOnArrival() const {
+ // Initialization of OpenGL binding may fail.
+ if (gl::GetGLImplementation() == gl::kGLImplementationNone)
+ return true;
+
+#if !defined(OS_MACOSX)
+ DCHECK_NE(gpu::kCollectInfoNone, gpu_info_.context_info_state);
+ if (gpu_info_.context_info_state == gpu::kCollectInfoFatalFailure)
+ return true;
+#endif
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ if (gpu_info_.gpu.vendor_id == 0x10de && // NVIDIA
+ gpu_info_.driver_vendor == "NVIDIA" && !CanAccessNvidiaDeviceFile())
+ return true;
+#endif
+ return false;
+}
+
+} // namespace gpu

Powered by Google App Engine
This is Rietveld 408576698