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"
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"
25 static base::LazyInstance
<scoped_refptr
<ThreadSafeSender
> >
26 g_thread_safe_sender
= LAZY_INSTANCE_INITIALIZER
;
28 bool GpuProcessLogMessageHandler(int severity
,
29 const char* file
, int line
,
31 const std::string
& str
) {
32 std::string header
= str
.substr(0, message_start
);
33 std::string message
= str
.substr(message_start
);
35 g_thread_safe_sender
.Get()->Send(new GpuHostMsg_OnLogMessage(
36 severity
, header
, message
));
43 GpuChildThread::GpuChildThread(GpuWatchdogThread
* watchdog_thread
,
45 const gpu::GPUInfo
& gpu_info
,
46 const DeferredMessages
& deferred_messages
)
47 : dead_on_arrival_(dead_on_arrival
),
49 deferred_messages_(deferred_messages
),
50 in_browser_process_(false) {
51 watchdog_thread_
= watchdog_thread
;
53 target_services_
= NULL
;
55 g_thread_safe_sender
.Get() = thread_safe_sender();
58 GpuChildThread::GpuChildThread(const std::string
& channel_id
)
59 : ChildThread(channel_id
),
60 dead_on_arrival_(false),
61 in_browser_process_(true) {
63 target_services_
= NULL
;
66 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess
) ||
67 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU
));
68 // For single process and in-process GPU mode, we need to load and
69 // initialize the GL implementation and locate the GL entry points here.
70 if (!gfx::GLSurface::InitializeOneOff()) {
71 VLOG(1) << "gfx::GLSurface::InitializeOneOff()";
73 g_thread_safe_sender
.Get() = thread_safe_sender();
76 GpuChildThread::~GpuChildThread() {
79 void GpuChildThread::Shutdown() {
80 ChildThread::Shutdown();
81 logging::SetLogMessageHandler(NULL
);
84 void GpuChildThread::Init(const base::Time
& process_start_time
) {
85 process_start_time_
= process_start_time
;
88 bool GpuChildThread::Send(IPC::Message
* msg
) {
89 // The GPU process must never send a synchronous IPC message to the browser
90 // process. This could result in deadlock.
91 DCHECK(!msg
->is_sync());
93 return ChildThread::Send(msg
);
96 bool GpuChildThread::OnControlMessageReceived(const IPC::Message
& msg
) {
97 bool msg_is_ok
= true;
99 IPC_BEGIN_MESSAGE_MAP_EX(GpuChildThread
, msg
, msg_is_ok
)
100 IPC_MESSAGE_HANDLER(GpuMsg_Initialize
, OnInitialize
)
101 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo
, OnCollectGraphicsInfo
)
102 IPC_MESSAGE_HANDLER(GpuMsg_GetVideoMemoryUsageStats
,
103 OnGetVideoMemoryUsageStats
)
104 IPC_MESSAGE_HANDLER(GpuMsg_Clean
, OnClean
)
105 IPC_MESSAGE_HANDLER(GpuMsg_Crash
, OnCrash
)
106 IPC_MESSAGE_HANDLER(GpuMsg_Hang
, OnHang
)
107 IPC_MESSAGE_HANDLER(GpuMsg_DisableWatchdog
, OnDisableWatchdog
)
108 IPC_MESSAGE_UNHANDLED(handled
= false)
109 IPC_END_MESSAGE_MAP_EX()
114 return gpu_channel_manager_
.get() &&
115 gpu_channel_manager_
->OnMessageReceived(msg
);
118 void GpuChildThread::OnInitialize() {
119 Send(new GpuHostMsg_Initialized(!dead_on_arrival_
, gpu_info_
));
120 while (!deferred_messages_
.empty()) {
121 Send(deferred_messages_
.front());
122 deferred_messages_
.pop();
125 if (dead_on_arrival_
) {
126 VLOG(1) << "Exiting GPU process due to errors during initialization";
127 base::MessageLoop::current()->Quit();
131 #if defined(OS_ANDROID)
132 base::PlatformThread::SetThreadPriority(
133 base::PlatformThread::CurrentHandle(),
134 base::kThreadPriority_Display
);
137 // We don't need to pipe log messages if we are running the GPU thread in
138 // the browser process.
139 if (!in_browser_process_
)
140 logging::SetLogMessageHandler(GpuProcessLogMessageHandler
);
142 // Record initialization only after collecting the GPU info because that can
143 // take a significant amount of time.
144 gpu_info_
.initialization_time
= base::Time::Now() - process_start_time_
;
146 // Defer creation of the render thread. This is to prevent it from handling
147 // IPC messages before the sandbox has been enabled and all other necessary
148 // initialization has succeeded.
149 gpu_channel_manager_
.reset(
150 new GpuChannelManager(this,
151 watchdog_thread_
.get(),
152 ChildProcess::current()->io_message_loop_proxy(),
153 ChildProcess::current()->GetShutDownEvent()));
155 // Ensure the browser process receives the GPU info before a reply to any
156 // subsequent IPC it might send.
157 if (!in_browser_process_
)
158 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_
));
161 void GpuChildThread::StopWatchdog() {
162 if (watchdog_thread_
.get()) {
163 watchdog_thread_
->Stop();
167 void GpuChildThread::OnCollectGraphicsInfo() {
169 // GPU full info collection should only happen on un-sandboxed GPU process
170 // or single process/in-process gpu mode on Windows.
171 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
172 DCHECK(command_line
->HasSwitch(switches::kDisableGpuSandbox
) ||
173 in_browser_process_
);
176 if (!gpu::CollectContextGraphicsInfo(&gpu_info_
))
177 VLOG(1) << "gpu::CollectGraphicsInfo failed";
178 GetContentClient()->SetGpuInfo(gpu_info_
);
181 // This is slow, but it's the only thing the unsandboxed GPU process does,
182 // and GpuDataManager prevents us from sending multiple collecting requests,
183 // so it's OK to be blocking.
184 gpu::GetDxDiagnostics(&gpu_info_
.dx_diagnostics
);
185 gpu_info_
.finalized
= true;
188 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_
));
191 if (!in_browser_process_
) {
192 // The unsandboxed GPU process fulfilled its duty. Rest in peace.
193 base::MessageLoop::current()->Quit();
198 void GpuChildThread::OnGetVideoMemoryUsageStats() {
199 GPUVideoMemoryUsageStats video_memory_usage_stats
;
200 if (gpu_channel_manager_
)
201 gpu_channel_manager_
->gpu_memory_manager()->GetVideoMemoryUsageStats(
202 &video_memory_usage_stats
);
203 Send(new GpuHostMsg_VideoMemoryUsageStats(video_memory_usage_stats
));
206 void GpuChildThread::OnClean() {
207 VLOG(1) << "GPU: Removing all contexts";
208 if (gpu_channel_manager_
)
209 gpu_channel_manager_
->LoseAllContexts();
212 void GpuChildThread::OnCrash() {
213 VLOG(1) << "GPU: Simulating GPU crash";
214 // Good bye, cruel world.
215 volatile int* it_s_the_end_of_the_world_as_we_know_it
= NULL
;
216 *it_s_the_end_of_the_world_as_we_know_it
= 0xdead;
219 void GpuChildThread::OnHang() {
220 VLOG(1) << "GPU: Simulating GPU hang";
222 // Do not sleep here. The GPU watchdog timer tracks the amount of user
223 // time this thread is using and it doesn't use much while calling Sleep.
227 void GpuChildThread::OnDisableWatchdog() {
228 VLOG(1) << "GPU: Disabling watchdog thread";
229 if (watchdog_thread_
.get()) {
230 // Disarm the watchdog before shutting down the message loop. This prevents
231 // the future posting of tasks to the message loop.
232 if (watchdog_thread_
->message_loop())
233 watchdog_thread_
->PostAcknowledge();
235 watchdog_thread_
->Stop();
239 } // namespace content