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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gpu/ipc/service/gpu_init.h"
6
7 #include "base/command_line.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
11 #include "base/threading/thread_restrictions.h"
12 #include "base/trace_event/trace_event.h"
13 #include "gpu/command_buffer/service/gpu_switches.h"
14 #include "gpu/config/gpu_driver_bug_list.h"
15 #include "gpu/config/gpu_info_collector.h"
16 #include "gpu/config/gpu_switches.h"
17 #include "gpu/config/gpu_util.h"
18 #include "gpu/ipc/service/gpu_watchdog_thread.h"
19 #include "gpu/ipc/service/switches.h"
20 #include "ui/gl/gl_implementation.h"
21 #include "ui/gl/gl_switches.h"
22 #include "ui/gl/init/gl_factory.h"
23
24 namespace gpu {
25
26 namespace {
27
28 void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info,
29 const base::CommandLine& command_line) {
30 if (!command_line.HasSwitch(switches::kGpuVendorID) ||
31 !command_line.HasSwitch(switches::kGpuDeviceID) ||
32 !command_line.HasSwitch(switches::kGpuDriverVersion))
33 return;
34 bool success = base::HexStringToUInt(
35 command_line.GetSwitchValueASCII(switches::kGpuVendorID),
36 &gpu_info.gpu.vendor_id);
37 DCHECK(success);
38 success = base::HexStringToUInt(
39 command_line.GetSwitchValueASCII(switches::kGpuDeviceID),
40 &gpu_info.gpu.device_id);
41 DCHECK(success);
42 gpu_info.driver_vendor =
43 command_line.GetSwitchValueASCII(switches::kGpuDriverVendor);
44 gpu_info.driver_version =
45 command_line.GetSwitchValueASCII(switches::kGpuDriverVersion);
46 gpu_info.driver_date =
47 command_line.GetSwitchValueASCII(switches::kGpuDriverDate);
48 gpu::ParseSecondaryGpuDevicesFromCommandLine(command_line, &gpu_info);
49
50 // Set active gpu device.
51 if (command_line.HasSwitch(switches::kGpuActiveVendorID) &&
52 command_line.HasSwitch(switches::kGpuActiveDeviceID)) {
53 uint32_t active_vendor_id = 0;
54 uint32_t active_device_id = 0;
55 success = base::HexStringToUInt(
56 command_line.GetSwitchValueASCII(switches::kGpuActiveVendorID),
57 &active_vendor_id);
58 DCHECK(success);
59 success = base::HexStringToUInt(
60 command_line.GetSwitchValueASCII(switches::kGpuActiveDeviceID),
61 &active_device_id);
62 DCHECK(success);
63 if (gpu_info.gpu.vendor_id == active_vendor_id &&
64 gpu_info.gpu.device_id == active_device_id) {
65 gpu_info.gpu.active = true;
66 } else {
67 for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) {
68 if (gpu_info.secondary_gpus[i].vendor_id == active_vendor_id &&
69 gpu_info.secondary_gpus[i].device_id == active_device_id) {
70 gpu_info.secondary_gpus[i].active = true;
71 break;
72 }
73 }
74 }
75 }
76 }
77
78 #if !defined(OS_MACOSX)
79 void CollectGraphicsInfo(gpu::GPUInfo& gpu_info) {
80 TRACE_EVENT0("gpu,startup", "Collect Graphics Info");
81
82 gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(&gpu_info);
83 switch (result) {
84 case gpu::kCollectInfoFatalFailure:
85 LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
86 break;
87 case gpu::kCollectInfoNonFatalFailure:
88 DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
89 break;
90 case gpu::kCollectInfoNone:
91 NOTREACHED();
92 break;
93 case gpu::kCollectInfoSuccess:
94 break;
95 }
96 }
97 #endif // defined(OS_MACOSX)
98
99 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
100 bool CanAccessNvidiaDeviceFile() {
101 bool res = true;
102 base::ThreadRestrictions::AssertIOAllowed();
103 if (access("/dev/nvidiactl", R_OK) != 0) {
104 DVLOG(1) << "NVIDIA device file /dev/nvidiactl access denied";
105 res = false;
106 }
107 return res;
108 }
109 #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
110
111 } // namespace
112
113 GpuInit::GpuInit() {}
114
115 GpuInit::~GpuInit() {}
116
117 void GpuInit::InitializeAndStartSandbox(const base::CommandLine& command_line) {
118 if (command_line.HasSwitch(switches::kSupportsDualGpus)) {
119 std::set<int> workarounds;
120 gpu::GpuDriverBugList::AppendWorkaroundsFromCommandLine(&workarounds,
121 command_line);
122 gpu::InitializeDualGpusIfSupported(workarounds);
123 }
124
125 // In addition to disabling the watchdog if the command line switch is
126 // present, disable the watchdog on valgrind because the code is expected
127 // to run slowly in that case.
128 bool enable_watchdog =
129 !command_line.HasSwitch(switches::kDisableGpuWatchdog) &&
130 !RunningOnValgrind();
131
132 // Disable the watchdog in debug builds because they tend to only be run by
133 // developers who will not appreciate the watchdog killing the GPU process.
134 #ifndef NDEBUG
135 enable_watchdog = false;
136 #endif
137
138 bool delayed_watchdog_enable = false;
139
140 #if defined(OS_CHROMEOS)
141 // Don't start watchdog immediately, to allow developers to switch to VT2 on
142 // startup.
143 delayed_watchdog_enable = true;
144 #endif
145
146 // Start the GPU watchdog only after anything that is expected to be time
147 // consuming has completed, otherwise the process is liable to be aborted.
148 if (enable_watchdog && !delayed_watchdog_enable)
149 watchdog_thread_ = gpu::GpuWatchdogThread::Create();
150
151 // Get vendor_id, device_id, driver_version from browser process through
152 // commandline switches.
153 GetGpuInfoFromCommandLine(gpu_info_, command_line);
154 gpu_info_.in_process_gpu = false;
155
156 sandbox_helper_->PreSandboxStartup();
157
158 #if defined(OS_LINUX)
159 // On Chrome OS ARM Mali, GPU driver userspace creates threads when
160 // initializing a GL context, so start the sandbox early.
161 if (command_line.HasSwitch(switches::kGpuSandboxStartEarly))
162 gpu_info_.sandboxed = sandbox_helper_->EnsureSandboxInitialized();
163 #endif // defined(OS_LINUX)
164
165 base::TimeTicks before_initialize_one_off = base::TimeTicks::Now();
166
167 // Initialization of the OpenGL bindings may fail, in which case we
168 // will need to tear down this process. However, we can not do so
169 // safely until the IPC channel is set up, because the detection of
170 // early return of a child process is implemented using an IPC
171 // channel error. If the IPC channel is not fully set up between the
172 // browser and GPU process, and the GPU process crashes or exits
173 // early, the browser process will never detect it. For this reason
174 // we defer tearing down the GPU process until receiving the
175 // GpuMsg_Initialize message from the browser.
176
177 // Load and initialize the GL implementation and locate the GL entry points
178 // if needed. This initialization may have already happened if running in
179 // the browser process, for example.
180 bool gl_initialized = gl::GetGLImplementation() != gl::kGLImplementationNone;
181 if (!gl_initialized)
182 gl_initialized = gl::init::InitializeGLOneOff();
183
184 if (gl_initialized) {
185 // We need to collect GL strings (VENDOR, RENDERER) for blacklisting
186 // purposes. However, on Mac we don't actually use them. As documented in
187 // crbug.com/222934, due to some driver issues, glGetString could take
188 // multiple seconds to finish, which in turn cause the GPU process to
189 // crash.
190 // By skipping the following code on Mac, we don't really lose anything,
191 // because the basic GPU information is passed down from browser process
192 // and we already registered them through SetGpuInfo() above.
193 base::TimeTicks before_collect_context_graphics_info =
194 base::TimeTicks::Now();
195 #if !defined(OS_MACOSX)
196 CollectGraphicsInfo(gpu_info_);
197
198 // Recompute gpu driver bug workarounds.
199 // This is necessary on systems where vendor_id/device_id aren't available
200 // (Chrome OS, Android) or where workarounds may be dependent on GL_VENDOR
201 // and GL_RENDERER strings which are lazily computed (Linux).
202 if (!command_line.HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
203 // TODO: this can not affect disabled extensions, since they're already
204 // initialized in the bindings. This should be moved before bindings
205 // initialization. However, populating GPUInfo fully works only on
206 // Android. Other platforms would need the bindings to query GL strings.
207 gpu::ApplyGpuDriverBugWorkarounds(
208 gpu_info_, const_cast<base::CommandLine*>(&command_line));
209 }
210 #endif // !defined(OS_MACOSX)
211
212 base::TimeDelta collect_context_time =
213 base::TimeTicks::Now() - before_collect_context_graphics_info;
214 UMA_HISTOGRAM_TIMES("GPU.CollectContextGraphicsInfo", collect_context_time);
215 } else { // gl_initialized
216 VLOG(1) << "gl::init::InitializeGLOneOff failed";
217 }
218
219 base::TimeDelta initialize_one_off_time =
220 base::TimeTicks::Now() - before_initialize_one_off;
221 UMA_HISTOGRAM_MEDIUM_TIMES("GPU.InitializeOneOffMediumTime",
222 initialize_one_off_time);
223 if (enable_watchdog && delayed_watchdog_enable)
224 watchdog_thread_ = gpu::GpuWatchdogThread::Create();
225
226 // OSMesa is expected to run very slowly, so disable the watchdog in that
227 // case.
228 if (enable_watchdog &&
229 gl::GetGLImplementation() == gl::kGLImplementationOSMesaGL) {
230 watchdog_thread_->Stop();
231 watchdog_thread_ = NULL;
232 }
233
234 // It is necessary to make the DOA decision before entering the sandbox
235 // (because on Linux, it can attempt to access a file).
236 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
237
238 if (!gpu_info_.sandboxed)
239 gpu_info_.sandboxed = sandbox_helper_->EnsureSandboxInitialized();
240 }
241
242 bool GpuInit::IsDeadOnArrival() const {
243 // Initialization of OpenGL binding may fail.
244 if (gl::GetGLImplementation() == gl::kGLImplementationNone)
245 return true;
246
247 #if !defined(OS_MACOSX)
248 DCHECK_NE(gpu::kCollectInfoNone, gpu_info_.context_info_state);
249 if (gpu_info_.context_info_state == gpu::kCollectInfoFatalFailure)
250 return true;
251 #endif
252 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
253 if (gpu_info_.gpu.vendor_id == 0x10de && // NVIDIA
254 gpu_info_.driver_vendor == "NVIDIA" && !CanAccessNvidiaDeviceFile())
255 return true;
256 #endif
257 return false;
258 }
259
260 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698