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

Side by Side Diff: gpu/ipc/service/gpu_init.cc

Issue 2289553002: 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
« no previous file with comments | « gpu/ipc/service/gpu_init.h ('k') | gpu/ipc/service/gpu_init_delegate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/lazy_instance.h"
8 #include "base/metrics/histogram.h"
9 #include "base/metrics/statistics_recorder.h"
10 #include "base/power_monitor/power_monitor.h"
11 #include "base/rand_util.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
16 #include "base/threading/platform_thread.h"
17 #include "base/trace_event/trace_event.h"
18 #include "build/build_config.h"
19 #include "gpu/command_buffer/service/gpu_switches.h"
20 #include "gpu/config/gpu_driver_bug_workaround_type.h"
21 #include "gpu/config/gpu_info_collector.h"
22 #include "gpu/config/gpu_switches.h"
23 #include "gpu/config/gpu_util.h"
24 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
25 #include "gpu/ipc/service/gpu_config.h"
26 #include "gpu/ipc/service/gpu_init_delegate.h"
27 #include "gpu/ipc/service/gpu_memory_buffer_factory.h"
28 #include "gpu/ipc/service/gpu_watchdog_thread.h"
29 #include "ui/events/platform/platform_event_source.h"
30 #include "ui/gl/gl_context.h"
31 #include "ui/gl/gl_implementation.h"
32 #include "ui/gl/gl_surface.h"
33 #include "ui/gl/gl_switches.h"
34 #include "ui/gl/gpu_switching_manager.h"
35 #include "ui/gl/init/gl_factory.h"
36
37 #if defined(OS_WIN)
38 #include <windows.h>
39 #include <dwmapi.h>
40 #endif
41
42 #if defined(USE_X11)
43 #include "ui/base/x/x11_util.h" // nogncheck
44 #endif
45
46 namespace gpu {
47
48 namespace {
49
50 base::LazyInstance<std::vector<GpuInitLogMessage>> deferred_messages =
51 LAZY_INSTANCE_INITIALIZER;
52
53 bool GpuProcessLogMessageHandler(int severity,
54 const char* file,
55 int line,
56 size_t message_start,
57 const std::string& str) {
58 std::string header = str.substr(0, message_start);
59 std::string message = str.substr(message_start);
60 deferred_messages.Get().push_back({severity, header, message});
61 return false;
62 }
63
64 void GetGpuInfoFromCommandLine(gpu::GPUInfo* gpu_info,
65 const base::CommandLine& command_line) {
66 if (!command_line.HasSwitch(switches::kGpuVendorID) ||
67 !command_line.HasSwitch(switches::kGpuDeviceID) ||
68 !command_line.HasSwitch(switches::kGpuDriverVersion))
69 return;
70 bool success = base::HexStringToUInt(
71 command_line.GetSwitchValueASCII(switches::kGpuVendorID),
72 &gpu_info->gpu.vendor_id);
73 DCHECK(success);
74 success = base::HexStringToUInt(
75 command_line.GetSwitchValueASCII(switches::kGpuDeviceID),
76 &gpu_info->gpu.device_id);
77 DCHECK(success);
78 gpu_info->driver_vendor =
79 command_line.GetSwitchValueASCII(switches::kGpuDriverVendor);
80 gpu_info->driver_version =
81 command_line.GetSwitchValueASCII(switches::kGpuDriverVersion);
82 gpu_info->driver_date =
83 command_line.GetSwitchValueASCII(switches::kGpuDriverDate);
84 gpu::ParseSecondaryGpuDevicesFromCommandLine(command_line, gpu_info);
85
86 // Set active gpu device.
87 if (command_line.HasSwitch(switches::kGpuActiveVendorID) &&
88 command_line.HasSwitch(switches::kGpuActiveDeviceID)) {
89 uint32_t active_vendor_id = 0;
90 uint32_t active_device_id = 0;
91 success = base::HexStringToUInt(
92 command_line.GetSwitchValueASCII(switches::kGpuActiveVendorID),
93 &active_vendor_id);
94 DCHECK(success);
95 success = base::HexStringToUInt(
96 command_line.GetSwitchValueASCII(switches::kGpuActiveDeviceID),
97 &active_device_id);
98 DCHECK(success);
99 if (gpu_info->gpu.vendor_id == active_vendor_id &&
100 gpu_info->gpu.device_id == active_device_id) {
101 gpu_info->gpu.active = true;
102 } else {
103 for (size_t i = 0; i < gpu_info->secondary_gpus.size(); ++i) {
104 if (gpu_info->secondary_gpus[i].vendor_id == active_vendor_id &&
105 gpu_info->secondary_gpus[i].device_id == active_device_id) {
106 gpu_info->secondary_gpus[i].active = true;
107 break;
108 }
109 }
110 }
111 }
112 }
113
114 #if !defined(OS_MACOSX)
115 bool CollectGraphicsInfo(gpu::GPUInfo* gpu_info) {
116 TRACE_EVENT0("gpu,startup", "Collect Graphics Info");
117
118 bool res = true;
119 gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(gpu_info);
120 switch (result) {
121 case gpu::kCollectInfoFatalFailure:
122 LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
123 res = false;
124 break;
125 case gpu::kCollectInfoNonFatalFailure:
126 DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
127 break;
128 case gpu::kCollectInfoNone:
129 NOTREACHED();
130 break;
131 case gpu::kCollectInfoSuccess:
132 break;
133 }
134 return res;
135 }
136 #endif // !defined(OS_MACOSX)
137
138 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
139 bool CanAccessNvidiaDeviceFile() {
140 bool res = true;
141 base::ThreadRestrictions::AssertIOAllowed();
142 if (access("/dev/nvidiactl", R_OK) != 0) {
143 DVLOG(1) << "NVIDIA device file /dev/nvidiactl access denied";
144 res = false;
145 }
146 return res;
147 }
148 #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
149
150 } // namespace
151
152 GpuInit::GpuInit(GpuInitDelegate* delegate,
153 const base::CommandLine& command_line)
154 : delegate_(delegate) {
155 if (command_line.HasSwitch(switches::kGpuStartupDialog)) {
156 delegate_->WaitForDebugger();
157 }
158
159 base::Time start_time = base::Time::Now();
160
161 #if defined(OS_WIN)
162 // Prevent Windows from displaying a modal dialog on failures like not being
163 // able to load a DLL.
164 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
165 SEM_NOOPENFILEERRORBOX);
166 #elif defined(USE_X11)
167 ui::SetDefaultX11ErrorHandlers();
168 #endif // defined(USE_X11)
169
170 logging::SetLogMessageHandler(GpuProcessLogMessageHandler);
171
172 if (command_line.HasSwitch(switches::kSupportsDualGpus)) {
173 std::string types =
174 command_line.GetSwitchValueASCII(switches::kGpuDriverBugWorkarounds);
175 std::set<int> workarounds;
176 gpu::StringToFeatureSet(types, &workarounds);
177 if (workarounds.count(gpu::FORCE_DISCRETE_GPU) == 1)
178 ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
179 else if (workarounds.count(gpu::FORCE_INTEGRATED_GPU) == 1)
180 ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
181 }
182
183 // Initialization of the OpenGL bindings may fail, in which case we
184 // will need to tear down this process. However, we can not do so
185 // safely until the IPC channel is set up, because the detection of
186 // early return of a child process is implemented using an IPC
187 // channel error. If the IPC channel is not fully set up between the
188 // browser and GPU process, and the GPU process crashes or exits
189 // early, the browser process will never detect it. For this reason
190 // we defer tearing down the GPU process until receiving the
191 // GpuMsg_Initialize message from the browser.
192 bool dead_on_arrival = false;
193
194 delegate_->InitializeMessageLoop();
195 base::PlatformThread::SetName("CrGpuMain");
196
197 // In addition to disabling the watchdog if the command line switch is
198 // present, disable the watchdog on valgrind because the code is expected
199 // to run slowly in that case.
200 bool enable_watchdog =
201 !command_line.HasSwitch(switches::kDisableGpuWatchdog) &&
202 !RunningOnValgrind();
203
204 // Disable the watchdog in debug builds because they tend to only be run by
205 // developers who will not appreciate the watchdog killing the GPU process.
206 #ifndef NDEBUG
207 enable_watchdog = false;
208 #endif
209
210 bool delayed_watchdog_enable = false;
211
212 #if defined(OS_CHROMEOS)
213 // Don't start watchdog immediately, to allow developers to switch to VT2 on
214 // startup.
215 delayed_watchdog_enable = true;
216 #endif
217
218 // Start the GPU watchdog only after anything that is expected to be time
219 // consuming has completed, otherwise the process is liable to be aborted.
220 if (enable_watchdog && !delayed_watchdog_enable) {
221 watchdog_thread_ = gpu::GpuWatchdogThread::Create();
222 delegate_->OnGpuWatchdogThreadCreated(watchdog_thread_.get());
223 }
224
225 // Initializes StatisticsRecorder which tracks UMA histograms.
226 base::StatisticsRecorder::Initialize();
227
228 gpu::GPUInfo gpu_info;
229 // Get vendor_id, device_id, driver_version from browser process through
230 // commandline switches.
231 GetGpuInfoFromCommandLine(&gpu_info, command_line);
232 gpu_info.in_process_gpu = false;
233 delegate_->OnGpuInfoUpdate(gpu_info);
234
235 delegate_->PreSandboxInitialization();
236
237 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
238 // Set thread priority before sandbox initialization.
239 base::PlatformThread::SetCurrentThreadPriority(base::ThreadPriority::DISPLAY);
240 #endif
241
242 // Warm up sandbox.
243 {
244 TRACE_EVENT0("gpu", "Warm up rand");
245 // Warm up the random subsystem, which needs to be done pre-sandbox on all
246 // platforms.
247 (void)base::RandUint64();
248 }
249 delegate_->WarmUpSandbox();
250
251 bool initialized_sandbox = false;
252 if (delegate_->ShouldStartSandboxEarly()) {
253 gpu_info.sandboxed = delegate_->StartSandbox();
254 initialized_sandbox = true;
255 }
256
257 base::TimeTicks before_initialize_one_off = base::TimeTicks::Now();
258
259 // Determine if we need to initialize GL here or it has already been done.
260 bool should_initialize_gl = delegate_->ShouldInitializeGL();
261
262 // Load and initialize the GL implementation and locate the GL entry points.
263 bool gl_initialized = should_initialize_gl ? gl::init::InitializeGLOneOff()
264 : gl::GetGLImplementation() !=
265 gl::kGLImplementationNone;
266 if (gl_initialized) {
267 // We need to collect GL strings (VENDOR, RENDERER) for blacklisting
268 // purposes. However, on Mac we don't actually use them. As documented in
269 // crbug.com/222934, due to some driver issues, glGetString could take
270 // multiple seconds to finish, which in turn cause the GPU process to
271 // crash.
272 // By skipping the following code on Mac, we don't really lose anything,
273 // because the basic GPU information is passed down from browser process
274 // and we already registered them through SetGpuInfo() above.
275 base::TimeTicks before_collect_context_graphics_info =
276 base::TimeTicks::Now();
277 #if !defined(OS_MACOSX)
278 if (!CollectGraphicsInfo(&gpu_info))
279 dead_on_arrival = true;
280 delegate_->OnGpuInfoUpdate(gpu_info);
281
282 // Recompute gpu driver bug workarounds.
283 // This is necessary on systems where vendor_id/device_id aren't available
284 // (Chrome OS, Android) or where workarounds may be dependent on GL_VENDOR
285 // and GL_RENDERER strings which are lazily computed (Linux).
286 if (!command_line.HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
287 // TODO: this can not affect disabled extensions, since they're already
288 // initialized in the bindings. This should be moved before bindings
289 // initialization. However, populating GPUInfo fully works only on
290 // Android. Other platforms would need the bindings to query GL strings.
291 gpu::ApplyGpuDriverBugWorkarounds(
292 gpu_info, const_cast<base::CommandLine*>(&command_line));
293 }
294 #endif // !defined(OS_MACOSX)
295
296 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
297 if (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA
298 gpu_info.driver_vendor == "NVIDIA" && !CanAccessNvidiaDeviceFile())
299 dead_on_arrival = true;
300 #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
301
302 base::TimeDelta collect_context_time =
303 base::TimeTicks::Now() - before_collect_context_graphics_info;
304 UMA_HISTOGRAM_TIMES("GPU.CollectContextGraphicsInfo", collect_context_time);
305 } else { // gl_initialized
306 VLOG(1) << "gl::init::InitializeGLOneOff failed";
307 dead_on_arrival = true;
308 }
309
310 base::TimeDelta initialize_one_off_time =
311 base::TimeTicks::Now() - before_initialize_one_off;
312 UMA_HISTOGRAM_MEDIUM_TIMES("GPU.InitializeOneOffMediumTime",
313 initialize_one_off_time);
314
315 if (enable_watchdog && delayed_watchdog_enable) {
316 watchdog_thread_ = gpu::GpuWatchdogThread::Create();
317 delegate_->OnGpuWatchdogThreadCreated(watchdog_thread_.get());
318 }
319
320 // OSMesa is expected to run very slowly, so disable the watchdog in that
321 // case.
322 if (enable_watchdog &&
323 gl::GetGLImplementation() == gl::kGLImplementationOSMesaGL) {
324 watchdog_thread_->Stop();
325 watchdog_thread_ = nullptr;
326 delegate_->OnGpuWatchdogThreadDestroyed();
327 }
328
329 if (!initialized_sandbox)
330 gpu_info.sandboxed = delegate_->StartSandbox();
331 delegate_->OnGpuInfoUpdate(gpu_info);
332
333 logging::SetLogMessageHandler(nullptr);
334
335 if (gpu::GetNativeGpuMemoryBufferType() != gfx::EMPTY_BUFFER)
336 gpu_memory_buffer_factory_ =
337 gpu::GpuMemoryBufferFactory::CreateNativeType();
338
339 delegate_->Initialize(start_time, dead_on_arrival,
340 std::move(deferred_messages.Get()),
341 gpu_memory_buffer_factory_.get());
342
343 if (watchdog_thread_ && base::PowerMonitor::Get())
344 watchdog_thread_->AddPowerObserver();
345 }
346
347 GpuInit::~GpuInit() {
348 if (watchdog_thread_)
349 watchdog_thread_->Stop();
350 }
351
352 } // namespace gpu
OLDNEW
« no previous file with comments | « gpu/ipc/service/gpu_init.h ('k') | gpu/ipc/service/gpu_init_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698