blob: 952dbc10f3bf0040216cb3e2fc50f855a2d293c2 [file] [log] [blame]
[email protected]f0918242012-02-18 00:30:501// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]c0fc0942010-01-13 00:55:372// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]7a31f7c2011-03-21 23:22:045#include "content/gpu/gpu_child_thread.h"
[email protected]c0fc0942010-01-13 00:55:376
[email protected]f658af8b2010-06-11 01:56:277#include <string>
8#include <vector>
[email protected]28638b22010-03-31 17:55:579
[email protected]80751052011-11-12 17:10:5810#include "base/bind.h"
[email protected]28638b22010-03-31 17:55:5711#include "base/command_line.h"
[email protected]ac9ba8fe2010-12-30 18:08:3612#include "base/threading/worker_pool.h"
[email protected]274aa5882010-07-15 21:12:2313#include "build/build_config.h"
[email protected]7ef40ffe12011-03-08 05:05:2814#include "content/common/child_process.h"
[email protected]202b54ff2011-04-22 21:36:3815#include "content/common/gpu/gpu_messages.h"
[email protected]623c0bd2011-03-12 01:00:4116#include "content/gpu/gpu_info_collector.h"
17#include "content/gpu/gpu_watchdog_thread.h"
[email protected]085170ca2012-05-17 20:27:2818#include "content/public/common/content_client.h"
[email protected]c9e2cbbb2012-05-12 21:17:2719#include "content/public/common/content_switches.h"
[email protected]939856a2010-08-24 20:29:0220#include "ipc/ipc_channel_handle.h"
[email protected]8c81e9ecc2012-04-25 00:42:2721#include "ipc/ipc_sync_message_filter.h"
[email protected]c9e2cbbb2012-05-12 21:17:2722#include "ui/gl/gl_implementation.h"
[email protected]7709e712011-01-07 17:57:3123
24const int kGpuTimeout = 10000;
25
26namespace {
27
[email protected]9158f2f2011-01-27 21:08:5728bool GpuProcessLogMessageHandler(int severity,
29 const char* file, int line,
30 size_t message_start,
31 const std::string& str) {
[email protected]e6ff5a32011-01-31 20:36:2232 std::string header = str.substr(0, message_start);
[email protected]9158f2f2011-01-27 21:08:5733 std::string message = str.substr(message_start);
[email protected]8c81e9ecc2012-04-25 00:42:2734
35 // If we are not on main thread in child process, send through
36 // the sync_message_filter; otherwise send directly.
37 if (MessageLoop::current() !=
38 ChildProcess::current()->main_thread()->message_loop()) {
39 ChildProcess::current()->main_thread()->sync_message_filter()->Send(
40 new GpuHostMsg_OnLogMessage(severity, header, message));
41 } else {
42 ChildThread::current()->Send(new GpuHostMsg_OnLogMessage(severity, header,
43 message));
44 }
45
[email protected]9158f2f2011-01-27 21:08:5746 return false;
47}
48
[email protected]e6ff5a32011-01-31 20:36:2249} // namespace
[email protected]9158f2f2011-01-27 21:08:5750
[email protected]f0918242012-02-18 00:30:5051GpuChildThread::GpuChildThread(bool dead_on_arrival,
52 const content::GPUInfo& gpu_info)
53 : dead_on_arrival_(dead_on_arrival),
54 gpu_info_(gpu_info) {
[email protected]7a31f7c2011-03-21 23:22:0455#if defined(OS_WIN)
[email protected]5abe6302011-12-20 23:44:3256 target_services_ = NULL;
[email protected]0b2cec62011-07-22 18:13:2857 collecting_dx_diagnostics_ = false;
[email protected]7a31f7c2011-03-21 23:22:0458#endif
[email protected]0b2cec62011-07-22 18:13:2859}
[email protected]9158f2f2011-01-27 21:08:5760
[email protected]7a31f7c2011-03-21 23:22:0461GpuChildThread::GpuChildThread(const std::string& channel_id)
[email protected]0b2cec62011-07-22 18:13:2862 : ChildThread(channel_id),
63 dead_on_arrival_(false) {
[email protected]7a31f7c2011-03-21 23:22:0464#if defined(OS_WIN)
65 target_services_ = NULL;
[email protected]5ea88812011-03-28 10:45:3966 collecting_dx_diagnostics_ = false;
[email protected]7a31f7c2011-03-21 23:22:0467#endif
[email protected]5750c522012-06-04 06:35:2568 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
69 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) {
70 // For single process and in-process GPU mode, we need to load and
71 // initialize the GL implementation and locate the GL entry points here.
72 if (!gfx::GLSurface::InitializeOneOff()) {
73 VLOG(1) << "gfx::GLSurface::InitializeOneOff()";
74 }
75 }
[email protected]7a31f7c2011-03-21 23:22:0476}
77
78
79GpuChildThread::~GpuChildThread() {
80 logging::SetLogMessageHandler(NULL);
81}
82
83void GpuChildThread::Init(const base::Time& process_start_time) {
84 process_start_time_ = process_start_time;
85}
86
87bool GpuChildThread::Send(IPC::Message* msg) {
88 // The GPU process must never send a synchronous IPC message to the browser
[email protected]4c0e289d2011-06-01 03:45:5189 // process. This could result in deadlock.
90 DCHECK(!msg->is_sync());
[email protected]7a31f7c2011-03-21 23:22:0491
92 return ChildThread::Send(msg);
93}
94
95bool GpuChildThread::OnControlMessageReceived(const IPC::Message& msg) {
96 bool msg_is_ok = true;
97 bool handled = true;
98 IPC_BEGIN_MESSAGE_MAP_EX(GpuChildThread, msg, msg_is_ok)
99 IPC_MESSAGE_HANDLER(GpuMsg_Initialize, OnInitialize)
100 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo)
[email protected]fb246af2012-08-18 03:11:41101 IPC_MESSAGE_HANDLER(GpuMsg_GetVideoMemoryUsageStats,
102 OnGetVideoMemoryUsageStats)
[email protected]184e3f3802011-05-04 20:48:52103 IPC_MESSAGE_HANDLER(GpuMsg_Clean, OnClean)
[email protected]7a31f7c2011-03-21 23:22:04104 IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash)
105 IPC_MESSAGE_HANDLER(GpuMsg_Hang, OnHang)
106 IPC_MESSAGE_UNHANDLED(handled = false)
107 IPC_END_MESSAGE_MAP_EX()
108
109 if (handled)
110 return true;
111
[email protected]f24a1e2b2011-04-08 01:48:48112 return gpu_channel_manager_.get() &&
113 gpu_channel_manager_->OnMessageReceived(msg);
[email protected]7a31f7c2011-03-21 23:22:04114}
115
116void GpuChildThread::OnInitialize() {
[email protected]96659732012-08-24 01:55:17117 Send(new GpuHostMsg_Initialized(!dead_on_arrival_));
118
[email protected]0b2cec62011-07-22 18:13:28119 if (dead_on_arrival_) {
[email protected]085170ca2012-05-17 20:27:28120 VLOG(1) << "Exiting GPU process due to errors during initialization";
[email protected]37cfa2a2012-08-20 20:29:39121 MessageLoop::current()->Quit();
122 return;
[email protected]0b2cec62011-07-22 18:13:28123 }
124
[email protected]2d9de4112011-05-27 03:18:36125 // We don't need to pipe log messages if we are running the GPU thread in
126 // the browser process.
127 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
128 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU))
129 logging::SetLogMessageHandler(GpuProcessLogMessageHandler);
[email protected]602cf9fda2011-04-22 16:53:30130
[email protected]e09cee42010-11-09 01:50:08131 // Record initialization only after collecting the GPU info because that can
132 // take a significant amount of time.
[email protected]a61508e52011-03-08 17:59:42133 gpu_info_.initialization_time = base::Time::Now() - process_start_time_;
[email protected]35312bf22011-01-06 23:07:20134
[email protected]7709e712011-01-07 17:57:31135 // In addition to disabling the watchdog if the command line switch is
136 // present, disable it in two other cases. OSMesa is expected to run very
137 // slowly. Also disable the watchdog on valgrind because the code is expected
138 // to run slowly in that case.
139 bool enable_watchdog =
[email protected]630c1f32011-01-13 21:30:56140 !CommandLine::ForCurrentProcess()->HasSwitch(
141 switches::kDisableGpuWatchdog) &&
[email protected]7709e712011-01-07 17:57:31142 gfx::GetGLImplementation() != gfx::kGLImplementationOSMesaGL &&
143 !RunningOnValgrind();
144
145 // Disable the watchdog in debug builds because they tend to only be run by
146 // developers who will not appreciate the watchdog killing the GPU process.
147#ifndef NDEBUG
148 enable_watchdog = false;
[email protected]a363c7a2011-01-06 23:25:50149#endif
[email protected]7709e712011-01-07 17:57:31150
[email protected]7709e712011-01-07 17:57:31151 // Start the GPU watchdog only after anything that is expected to be time
152 // consuming has completed, otherwise the process is liable to be aborted.
153 if (enable_watchdog) {
154 watchdog_thread_ = new GpuWatchdogThread(kGpuTimeout);
155 watchdog_thread_->Start();
156 }
[email protected]7a31f7c2011-03-21 23:22:04157
158 // Defer creation of the render thread. This is to prevent it from handling
159 // IPC messages before the sandbox has been enabled and all other necessary
160 // initialization has succeeded.
[email protected]f24a1e2b2011-04-08 01:48:48161 gpu_channel_manager_.reset(new GpuChannelManager(
[email protected]7a31f7c2011-03-21 23:22:04162 this,
[email protected]808f7fe72011-03-23 03:49:02163 watchdog_thread_,
[email protected]92bf9062011-05-02 18:00:49164 ChildProcess::current()->io_message_loop_proxy(),
[email protected]7a31f7c2011-03-21 23:22:04165 ChildProcess::current()->GetShutDownEvent()));
166
[email protected]085170ca2012-05-17 20:27:28167#if defined(OS_LINUX)
[email protected]7a31f7c2011-03-21 23:22:04168 // Ensure the browser process receives the GPU info before a reply to any
169 // subsequent IPC it might send.
[email protected]198e0c442011-12-02 19:45:06170 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_));
[email protected]085170ca2012-05-17 20:27:28171#endif
[email protected]7709e712011-01-07 17:57:31172}
173
[email protected]7a31f7c2011-03-21 23:22:04174void GpuChildThread::StopWatchdog() {
[email protected]7709e712011-01-07 17:57:31175 if (watchdog_thread_.get()) {
176 watchdog_thread_->Stop();
177 }
[email protected]c0fc0942010-01-13 00:55:37178}
179
[email protected]7a31f7c2011-03-21 23:22:04180void GpuChildThread::OnCollectGraphicsInfo() {
[email protected]085170ca2012-05-17 20:27:28181 if (!gpu_info_.finalized &&
[email protected]5750c522012-06-04 06:35:25182 (CommandLine::ForCurrentProcess()->HasSwitch(
183 switches::kDisableGpuSandbox) ||
184 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
185 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU))) {
186 // GPU full info collection should only happen on un-sandboxed GPU process
187 // or single process/in-process gpu mode.
[email protected]f3f79b102011-01-27 00:19:37188
[email protected]085170ca2012-05-17 20:27:28189 if (!gpu_info_collector::CollectGraphicsInfo(&gpu_info_))
190 VLOG(1) << "gpu_info_collector::CollectGraphicsInfo failed";
191 content::GetContentClient()->SetGpuInfo(gpu_info_);
192
193#if defined(OS_WIN)
194 if (!collecting_dx_diagnostics_) {
195 // Prevent concurrent collection of DirectX diagnostics.
196 collecting_dx_diagnostics_ = true;
197
[email protected]6f1485ee2012-01-28 00:29:19198 // Asynchronously collect the DirectX diagnostics because this can take a
199 // couple of seconds.
200 if (!base::WorkerPool::PostTask(
201 FROM_HERE, base::Bind(&GpuChildThread::CollectDxDiagnostics, this),
202 true)) {
203 // Flag GPU info as complete if the DirectX diagnostics cannot be
204 // collected.
205 collecting_dx_diagnostics_ = false;
206 gpu_info_.finalized = true;
[email protected]6f1485ee2012-01-28 00:29:19207 }
[email protected]f3f79b102011-01-27 00:19:37208 }
[email protected]f3f79b102011-01-27 00:19:37209#endif
[email protected]085170ca2012-05-17 20:27:28210 }
[email protected]e09cee42010-11-09 01:50:08211 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_));
[email protected]cadc0502010-09-10 20:27:13212}
[email protected]43ed6282010-09-15 20:07:19213
[email protected]fb246af2012-08-18 03:11:41214void GpuChildThread::OnGetVideoMemoryUsageStats() {
215 content::GPUVideoMemoryUsageStats video_memory_usage_stats;
216 if (gpu_channel_manager_.get())
217 gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
218 video_memory_usage_stats);
219 Send(new GpuHostMsg_VideoMemoryUsageStats(video_memory_usage_stats));
220}
221
[email protected]184e3f3802011-05-04 20:48:52222void GpuChildThread::OnClean() {
[email protected]085170ca2012-05-17 20:27:28223 VLOG(1) << "GPU: Removing all contexts";
[email protected]184e3f3802011-05-04 20:48:52224 if (gpu_channel_manager_.get())
225 gpu_channel_manager_->LoseAllContexts();
226}
227
[email protected]7a31f7c2011-03-21 23:22:04228void GpuChildThread::OnCrash() {
[email protected]085170ca2012-05-17 20:27:28229 VLOG(1) << "GPU: Simulating GPU crash";
[email protected]43ed6282010-09-15 20:07:19230 // Good bye, cruel world.
231 volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
232 *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
233}
[email protected]259750d2010-09-24 06:14:00234
[email protected]7a31f7c2011-03-21 23:22:04235void GpuChildThread::OnHang() {
[email protected]085170ca2012-05-17 20:27:28236 VLOG(1) << "GPU: Simulating GPU hang";
[email protected]981c1c52010-12-01 20:09:24237 for (;;) {
238 // Do not sleep here. The GPU watchdog timer tracks the amount of user
239 // time this thread is using and it doesn't use much while calling Sleep.
240 }
[email protected]259750d2010-09-24 06:14:00241}
[email protected]41579ae2010-11-15 22:31:26242
243#if defined(OS_WIN)
244
[email protected]7a31f7c2011-03-21 23:22:04245// Runs on a worker thread. The GPU process never terminates voluntarily so
246// it is safe to assume that its message loop is valid.
247void GpuChildThread::CollectDxDiagnostics(GpuChildThread* thread) {
[email protected]a80f5ece2011-10-20 23:56:55248 content::DxDiagNode node;
[email protected]41579ae2010-11-15 22:31:26249 gpu_info_collector::GetDxDiagnostics(&node);
250
251 thread->message_loop()->PostTask(
[email protected]80751052011-11-12 17:10:58252 FROM_HERE, base::Bind(&GpuChildThread::SetDxDiagnostics, thread, node));
[email protected]41579ae2010-11-15 22:31:26253}
254
[email protected]7a31f7c2011-03-21 23:22:04255// Runs on the main thread.
256void GpuChildThread::SetDxDiagnostics(GpuChildThread* thread,
[email protected]a80f5ece2011-10-20 23:56:55257 const content::DxDiagNode& node) {
[email protected]a61508e52011-03-08 17:59:42258 thread->gpu_info_.dx_diagnostics = node;
[email protected]6cc8ece62011-03-14 20:05:47259 thread->gpu_info_.finalized = true;
260 thread->collecting_dx_diagnostics_ = false;
[email protected]dfb26432011-02-24 21:03:03261 thread->Send(new GpuHostMsg_GraphicsInfoCollected(thread->gpu_info_));
[email protected]41579ae2010-11-15 22:31:26262}
263
264#endif