Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / gpu / gpu_child_thread.cc
blob4f774464649fbf94d3de2315b105657b5d94cb01
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"
22 #if defined(USE_OZONE)
23 #include "ui/ozone/public/gpu_platform_support.h"
24 #include "ui/ozone/public/ozone_platform.h"
25 #endif
27 namespace content {
28 namespace {
30 static base::LazyInstance<scoped_refptr<ThreadSafeSender> >
31 g_thread_safe_sender = LAZY_INSTANCE_INITIALIZER;
33 bool GpuProcessLogMessageHandler(int severity,
34 const char* file, int line,
35 size_t message_start,
36 const std::string& str) {
37 std::string header = str.substr(0, message_start);
38 std::string message = str.substr(message_start);
40 g_thread_safe_sender.Get()->Send(new GpuHostMsg_OnLogMessage(
41 severity, header, message));
43 return false;
46 } // namespace
48 GpuChildThread::GpuChildThread(GpuWatchdogThread* watchdog_thread,
49 bool dead_on_arrival,
50 const gpu::GPUInfo& gpu_info,
51 const DeferredMessages& deferred_messages)
52 : dead_on_arrival_(dead_on_arrival),
53 gpu_info_(gpu_info),
54 deferred_messages_(deferred_messages),
55 in_browser_process_(false) {
56 watchdog_thread_ = watchdog_thread;
57 #if defined(OS_WIN)
58 target_services_ = NULL;
59 #endif
60 g_thread_safe_sender.Get() = thread_safe_sender();
63 GpuChildThread::GpuChildThread(const std::string& channel_id)
64 : ChildThread(Options(channel_id, false)),
65 dead_on_arrival_(false),
66 in_browser_process_(true) {
67 #if defined(OS_WIN)
68 target_services_ = NULL;
69 #endif
70 DCHECK(
71 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
72 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU));
73 #if !defined(OS_ANDROID)
74 // For single process and in-process GPU mode, we need to load and
75 // initialize the GL implementation and locate the GL entry points here.
76 // On Android, GLSurface::InitializeOneOff() is called from BrowserMainLoop
77 // before getting here. crbug.com/326295
78 if (!gfx::GLSurface::InitializeOneOff())
79 VLOG(1) << "gfx::GLSurface::InitializeOneOff failed";
80 #endif
81 g_thread_safe_sender.Get() = thread_safe_sender();
84 GpuChildThread::~GpuChildThread() {
87 void GpuChildThread::Shutdown() {
88 ChildThread::Shutdown();
89 logging::SetLogMessageHandler(NULL);
92 void GpuChildThread::Init(const base::Time& process_start_time) {
93 process_start_time_ = process_start_time;
96 bool GpuChildThread::Send(IPC::Message* msg) {
97 // The GPU process must never send a synchronous IPC message to the browser
98 // process. This could result in deadlock.
99 DCHECK(!msg->is_sync());
101 return ChildThread::Send(msg);
104 bool GpuChildThread::OnControlMessageReceived(const IPC::Message& msg) {
105 bool handled = true;
106 IPC_BEGIN_MESSAGE_MAP(GpuChildThread, msg)
107 IPC_MESSAGE_HANDLER(GpuMsg_Initialize, OnInitialize)
108 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo)
109 IPC_MESSAGE_HANDLER(GpuMsg_GetVideoMemoryUsageStats,
110 OnGetVideoMemoryUsageStats)
111 IPC_MESSAGE_HANDLER(GpuMsg_Clean, OnClean)
112 IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash)
113 IPC_MESSAGE_HANDLER(GpuMsg_Hang, OnHang)
114 IPC_MESSAGE_HANDLER(GpuMsg_DisableWatchdog, OnDisableWatchdog)
115 IPC_MESSAGE_UNHANDLED(handled = false)
116 IPC_END_MESSAGE_MAP()
118 if (handled)
119 return true;
121 #if defined(USE_OZONE)
122 if (ui::OzonePlatform::GetInstance()
123 ->GetGpuPlatformSupport()
124 ->OnMessageReceived(msg))
125 return true;
126 #endif
128 return gpu_channel_manager_.get() &&
129 gpu_channel_manager_->OnMessageReceived(msg);
132 void GpuChildThread::OnInitialize() {
133 // Record initialization only after collecting the GPU info because that can
134 // take a significant amount of time.
135 gpu_info_.initialization_time = base::Time::Now() - process_start_time_;
136 Send(new GpuHostMsg_Initialized(!dead_on_arrival_, gpu_info_));
137 while (!deferred_messages_.empty()) {
138 Send(deferred_messages_.front());
139 deferred_messages_.pop();
142 if (dead_on_arrival_) {
143 LOG(ERROR) << "Exiting GPU process due to errors during initialization";
144 base::MessageLoop::current()->Quit();
145 return;
148 #if defined(OS_ANDROID)
149 base::PlatformThread::SetThreadPriority(
150 base::PlatformThread::CurrentHandle(),
151 base::kThreadPriority_Display);
152 #endif
154 // We don't need to pipe log messages if we are running the GPU thread in
155 // the browser process.
156 if (!in_browser_process_)
157 logging::SetLogMessageHandler(GpuProcessLogMessageHandler);
159 // Defer creation of the render thread. This is to prevent it from handling
160 // IPC messages before the sandbox has been enabled and all other necessary
161 // initialization has succeeded.
162 gpu_channel_manager_.reset(
163 new GpuChannelManager(GetRouter(),
164 watchdog_thread_.get(),
165 ChildProcess::current()->io_message_loop_proxy(),
166 ChildProcess::current()->GetShutDownEvent()));
168 #if defined(USE_OZONE)
169 ui::OzonePlatform::GetInstance()
170 ->GetGpuPlatformSupport()
171 ->OnChannelEstablished(this);
172 #endif
175 void GpuChildThread::StopWatchdog() {
176 if (watchdog_thread_.get()) {
177 watchdog_thread_->Stop();
181 void GpuChildThread::OnCollectGraphicsInfo() {
182 #if defined(OS_WIN)
183 // GPU full info collection should only happen on un-sandboxed GPU process
184 // or single process/in-process gpu mode on Windows.
185 CommandLine* command_line = CommandLine::ForCurrentProcess();
186 DCHECK(command_line->HasSwitch(switches::kDisableGpuSandbox) ||
187 in_browser_process_);
188 #endif // OS_WIN
190 gpu::CollectInfoResult result =
191 gpu::CollectContextGraphicsInfo(&gpu_info_);
192 switch (result) {
193 case gpu::kCollectInfoFatalFailure:
194 LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
195 // TODO(piman): can we signal overall failure?
196 break;
197 case gpu::kCollectInfoNonFatalFailure:
198 VLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
199 break;
200 case gpu::kCollectInfoSuccess:
201 break;
203 GetContentClient()->SetGpuInfo(gpu_info_);
205 #if defined(OS_WIN)
206 // This is slow, but it's the only thing the unsandboxed GPU process does,
207 // and GpuDataManager prevents us from sending multiple collecting requests,
208 // so it's OK to be blocking.
209 gpu::GetDxDiagnostics(&gpu_info_.dx_diagnostics);
210 gpu_info_.finalized = true;
211 #endif // OS_WIN
213 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_));
215 #if defined(OS_WIN)
216 if (!in_browser_process_) {
217 // The unsandboxed GPU process fulfilled its duty. Rest in peace.
218 base::MessageLoop::current()->Quit();
220 #endif // OS_WIN
223 void GpuChildThread::OnGetVideoMemoryUsageStats() {
224 GPUVideoMemoryUsageStats video_memory_usage_stats;
225 if (gpu_channel_manager_)
226 gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
227 &video_memory_usage_stats);
228 Send(new GpuHostMsg_VideoMemoryUsageStats(video_memory_usage_stats));
231 void GpuChildThread::OnClean() {
232 VLOG(1) << "GPU: Removing all contexts";
233 if (gpu_channel_manager_)
234 gpu_channel_manager_->LoseAllContexts();
237 void GpuChildThread::OnCrash() {
238 VLOG(1) << "GPU: Simulating GPU crash";
239 // Good bye, cruel world.
240 volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
241 *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
244 void GpuChildThread::OnHang() {
245 VLOG(1) << "GPU: Simulating GPU hang";
246 for (;;) {
247 // Do not sleep here. The GPU watchdog timer tracks the amount of user
248 // time this thread is using and it doesn't use much while calling Sleep.
252 void GpuChildThread::OnDisableWatchdog() {
253 VLOG(1) << "GPU: Disabling watchdog thread";
254 if (watchdog_thread_.get()) {
255 // Disarm the watchdog before shutting down the message loop. This prevents
256 // the future posting of tasks to the message loop.
257 if (watchdog_thread_->message_loop())
258 watchdog_thread_->PostAcknowledge();
259 // Prevent rearming.
260 watchdog_thread_->Stop();
264 } // namespace content