Convert events_unittests to run exclusively on Swarming
[chromium-blink-merge.git] / content / gpu / gpu_child_thread.cc
blob916d88abfbe16dae2a25f58fa428328dd7de3fc4
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
3 // found in the LICENSE file.
5 #include "content/gpu/gpu_child_thread.h"
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/threading/worker_pool.h"
10 #include "build/build_config.h"
11 #include "content/child/child_process.h"
12 #include "content/child/thread_safe_sender.h"
13 #include "content/common/gpu/gpu_messages.h"
14 #include "content/gpu/gpu_watchdog_thread.h"
15 #include "content/public/common/content_client.h"
16 #include "content/public/common/content_switches.h"
17 #include "gpu/config/gpu_info_collector.h"
18 #include "ipc/ipc_channel_handle.h"
19 #include "ipc/ipc_sync_message_filter.h"
20 #include "ui/gl/gl_implementation.h"
21 #include "ui/gl/gpu_switching_manager.h"
23 #if defined(USE_OZONE)
24 #include "ui/ozone/public/gpu_platform_support.h"
25 #include "ui/ozone/public/ozone_platform.h"
26 #endif
28 namespace content {
29 namespace {
31 static base::LazyInstance<scoped_refptr<ThreadSafeSender> >
32 g_thread_safe_sender = LAZY_INSTANCE_INITIALIZER;
34 bool GpuProcessLogMessageHandler(int severity,
35 const char* file, int line,
36 size_t message_start,
37 const std::string& str) {
38 std::string header = str.substr(0, message_start);
39 std::string message = str.substr(message_start);
41 g_thread_safe_sender.Get()->Send(new GpuHostMsg_OnLogMessage(
42 severity, header, message));
44 return false;
47 ChildThreadImpl::Options GetOptions() {
48 ChildThreadImpl::Options::Builder builder;
50 #if defined(USE_OZONE)
51 IPC::MessageFilter* message_filter = ui::OzonePlatform::GetInstance()
52 ->GetGpuPlatformSupport()
53 ->GetMessageFilter();
54 if (message_filter)
55 builder.AddStartupFilter(message_filter);
56 #endif
58 return builder.Build();
61 } // namespace
63 GpuChildThread::GpuChildThread(GpuWatchdogThread* watchdog_thread,
64 bool dead_on_arrival,
65 const gpu::GPUInfo& gpu_info,
66 const DeferredMessages& deferred_messages)
67 : ChildThreadImpl(GetOptions()),
68 dead_on_arrival_(dead_on_arrival),
69 gpu_info_(gpu_info),
70 deferred_messages_(deferred_messages),
71 in_browser_process_(false) {
72 watchdog_thread_ = watchdog_thread;
73 #if defined(OS_WIN)
74 target_services_ = NULL;
75 #endif
76 g_thread_safe_sender.Get() = thread_safe_sender();
79 GpuChildThread::GpuChildThread(const InProcessChildThreadParams& params)
80 : ChildThreadImpl(ChildThreadImpl::Options::Builder()
81 .InBrowserProcess(params)
82 .Build()),
83 dead_on_arrival_(false),
84 in_browser_process_(true) {
85 #if defined(OS_WIN)
86 target_services_ = NULL;
87 #endif
88 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
89 switches::kSingleProcess) ||
90 base::CommandLine::ForCurrentProcess()->HasSwitch(
91 switches::kInProcessGPU));
93 if (!gfx::GLSurface::InitializeOneOff())
94 VLOG(1) << "gfx::GLSurface::InitializeOneOff failed";
96 g_thread_safe_sender.Get() = thread_safe_sender();
99 GpuChildThread::~GpuChildThread() {
102 void GpuChildThread::Shutdown() {
103 ChildThreadImpl::Shutdown();
104 logging::SetLogMessageHandler(NULL);
107 void GpuChildThread::Init(const base::Time& process_start_time) {
108 process_start_time_ = process_start_time;
111 bool GpuChildThread::Send(IPC::Message* msg) {
112 // The GPU process must never send a synchronous IPC message to the browser
113 // process. This could result in deadlock.
114 DCHECK(!msg->is_sync());
116 return ChildThreadImpl::Send(msg);
119 bool GpuChildThread::OnControlMessageReceived(const IPC::Message& msg) {
120 bool handled = true;
121 IPC_BEGIN_MESSAGE_MAP(GpuChildThread, msg)
122 IPC_MESSAGE_HANDLER(GpuMsg_Initialize, OnInitialize)
123 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo)
124 IPC_MESSAGE_HANDLER(GpuMsg_GetVideoMemoryUsageStats,
125 OnGetVideoMemoryUsageStats)
126 IPC_MESSAGE_HANDLER(GpuMsg_Clean, OnClean)
127 IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash)
128 IPC_MESSAGE_HANDLER(GpuMsg_Hang, OnHang)
129 IPC_MESSAGE_HANDLER(GpuMsg_DisableWatchdog, OnDisableWatchdog)
130 IPC_MESSAGE_HANDLER(GpuMsg_GpuSwitched, OnGpuSwitched)
131 IPC_MESSAGE_UNHANDLED(handled = false)
132 IPC_END_MESSAGE_MAP()
134 if (handled)
135 return true;
137 #if defined(USE_OZONE)
138 if (ui::OzonePlatform::GetInstance()
139 ->GetGpuPlatformSupport()
140 ->OnMessageReceived(msg))
141 return true;
142 #endif
144 return gpu_channel_manager_.get() &&
145 gpu_channel_manager_->OnMessageReceived(msg);
148 void GpuChildThread::OnInitialize() {
149 // Record initialization only after collecting the GPU info because that can
150 // take a significant amount of time.
151 gpu_info_.initialization_time = base::Time::Now() - process_start_time_;
152 Send(new GpuHostMsg_Initialized(!dead_on_arrival_, gpu_info_));
153 while (!deferred_messages_.empty()) {
154 Send(deferred_messages_.front());
155 deferred_messages_.pop();
158 if (dead_on_arrival_) {
159 LOG(ERROR) << "Exiting GPU process due to errors during initialization";
160 base::MessageLoop::current()->Quit();
161 return;
164 #if defined(OS_ANDROID)
165 base::PlatformThread::SetThreadPriority(base::PlatformThread::CurrentHandle(),
166 base::ThreadPriority::DISPLAY);
167 #endif
169 // We don't need to pipe log messages if we are running the GPU thread in
170 // the browser process.
171 if (!in_browser_process_)
172 logging::SetLogMessageHandler(GpuProcessLogMessageHandler);
174 // Defer creation of the render thread. This is to prevent it from handling
175 // IPC messages before the sandbox has been enabled and all other necessary
176 // initialization has succeeded.
177 gpu_channel_manager_.reset(
178 new GpuChannelManager(GetRouter(), watchdog_thread_.get(),
179 ChildProcess::current()->io_task_runner(),
180 ChildProcess::current()->GetShutDownEvent(),
181 channel(), GetAttachmentBroker()));
183 #if defined(USE_OZONE)
184 ui::OzonePlatform::GetInstance()
185 ->GetGpuPlatformSupport()
186 ->OnChannelEstablished(this);
187 #endif
190 void GpuChildThread::StopWatchdog() {
191 if (watchdog_thread_.get()) {
192 watchdog_thread_->Stop();
196 void GpuChildThread::OnCollectGraphicsInfo() {
197 #if defined(OS_WIN)
198 // GPU full info collection should only happen on un-sandboxed GPU process
199 // or single process/in-process gpu mode on Windows.
200 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
201 DCHECK(command_line->HasSwitch(switches::kDisableGpuSandbox) ||
202 in_browser_process_);
203 #endif // OS_WIN
205 gpu::CollectInfoResult result =
206 gpu::CollectContextGraphicsInfo(&gpu_info_);
207 switch (result) {
208 case gpu::kCollectInfoFatalFailure:
209 LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
210 // TODO(piman): can we signal overall failure?
211 break;
212 case gpu::kCollectInfoNonFatalFailure:
213 DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
214 break;
215 case gpu::kCollectInfoNone:
216 NOTREACHED();
217 break;
218 case gpu::kCollectInfoSuccess:
219 break;
221 GetContentClient()->SetGpuInfo(gpu_info_);
223 #if defined(OS_WIN)
224 // This is slow, but it's the only thing the unsandboxed GPU process does,
225 // and GpuDataManager prevents us from sending multiple collecting requests,
226 // so it's OK to be blocking.
227 gpu::GetDxDiagnostics(&gpu_info_.dx_diagnostics);
228 gpu_info_.dx_diagnostics_info_state = gpu::kCollectInfoSuccess;
229 #endif // OS_WIN
231 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_));
233 #if defined(OS_WIN)
234 if (!in_browser_process_) {
235 // The unsandboxed GPU process fulfilled its duty. Rest in peace.
236 base::MessageLoop::current()->Quit();
238 #endif // OS_WIN
241 void GpuChildThread::OnGetVideoMemoryUsageStats() {
242 GPUVideoMemoryUsageStats video_memory_usage_stats;
243 if (gpu_channel_manager_)
244 gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
245 &video_memory_usage_stats);
246 Send(new GpuHostMsg_VideoMemoryUsageStats(video_memory_usage_stats));
249 void GpuChildThread::OnClean() {
250 DVLOG(1) << "GPU: Removing all contexts";
251 if (gpu_channel_manager_)
252 gpu_channel_manager_->LoseAllContexts();
255 void GpuChildThread::OnCrash() {
256 DVLOG(1) << "GPU: Simulating GPU crash";
257 // Good bye, cruel world.
258 volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
259 *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
262 void GpuChildThread::OnHang() {
263 DVLOG(1) << "GPU: Simulating GPU hang";
264 for (;;) {
265 // Do not sleep here. The GPU watchdog timer tracks the amount of user
266 // time this thread is using and it doesn't use much while calling Sleep.
270 void GpuChildThread::OnDisableWatchdog() {
271 DVLOG(1) << "GPU: Disabling watchdog thread";
272 if (watchdog_thread_.get()) {
273 // Disarm the watchdog before shutting down the message loop. This prevents
274 // the future posting of tasks to the message loop.
275 if (watchdog_thread_->message_loop())
276 watchdog_thread_->PostAcknowledge();
277 // Prevent rearming.
278 watchdog_thread_->Stop();
282 void GpuChildThread::OnGpuSwitched() {
283 DVLOG(1) << "GPU: GPU has switched";
284 // Notify observers in the GPU process.
285 ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
288 } // namespace content