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"
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"
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
,
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
));
47 ChildThreadImpl::Options
GetOptions() {
48 ChildThreadImpl::Options::Builder builder
;
50 #if defined(USE_OZONE)
51 IPC::MessageFilter
* message_filter
= ui::OzonePlatform::GetInstance()
52 ->GetGpuPlatformSupport()
55 builder
.AddStartupFilter(message_filter
);
58 return builder
.Build();
63 GpuChildThread::GpuChildThread(GpuWatchdogThread
* watchdog_thread
,
65 const gpu::GPUInfo
& gpu_info
,
66 const DeferredMessages
& deferred_messages
)
67 : ChildThreadImpl(GetOptions()),
68 dead_on_arrival_(dead_on_arrival
),
70 deferred_messages_(deferred_messages
),
71 in_browser_process_(false) {
72 watchdog_thread_
= watchdog_thread
;
74 target_services_
= NULL
;
76 g_thread_safe_sender
.Get() = thread_safe_sender();
79 GpuChildThread::GpuChildThread(const InProcessChildThreadParams
& params
)
80 : ChildThreadImpl(ChildThreadImpl::Options::Builder()
81 .InBrowserProcess(params
)
83 dead_on_arrival_(false),
84 in_browser_process_(true) {
86 target_services_
= NULL
;
88 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
89 switches::kSingleProcess
) ||
90 base::CommandLine::ForCurrentProcess()->HasSwitch(
91 switches::kInProcessGPU
));
92 #if !defined(OS_ANDROID)
93 // For single process and in-process GPU mode, we need to load and
94 // initialize the GL implementation and locate the GL entry points here.
95 // On Android, GLSurface::InitializeOneOff() is called from BrowserMainLoop
96 // before getting here. crbug.com/326295
97 if (!gfx::GLSurface::InitializeOneOff())
98 VLOG(1) << "gfx::GLSurface::InitializeOneOff failed";
100 g_thread_safe_sender
.Get() = thread_safe_sender();
103 GpuChildThread::~GpuChildThread() {
106 void GpuChildThread::Shutdown() {
107 ChildThreadImpl::Shutdown();
108 logging::SetLogMessageHandler(NULL
);
111 void GpuChildThread::Init(const base::Time
& process_start_time
) {
112 process_start_time_
= process_start_time
;
115 bool GpuChildThread::Send(IPC::Message
* msg
) {
116 // The GPU process must never send a synchronous IPC message to the browser
117 // process. This could result in deadlock.
118 DCHECK(!msg
->is_sync());
120 return ChildThreadImpl::Send(msg
);
123 bool GpuChildThread::OnControlMessageReceived(const IPC::Message
& msg
) {
125 IPC_BEGIN_MESSAGE_MAP(GpuChildThread
, msg
)
126 IPC_MESSAGE_HANDLER(GpuMsg_Initialize
, OnInitialize
)
127 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo
, OnCollectGraphicsInfo
)
128 IPC_MESSAGE_HANDLER(GpuMsg_GetVideoMemoryUsageStats
,
129 OnGetVideoMemoryUsageStats
)
130 IPC_MESSAGE_HANDLER(GpuMsg_Clean
, OnClean
)
131 IPC_MESSAGE_HANDLER(GpuMsg_Crash
, OnCrash
)
132 IPC_MESSAGE_HANDLER(GpuMsg_Hang
, OnHang
)
133 IPC_MESSAGE_HANDLER(GpuMsg_DisableWatchdog
, OnDisableWatchdog
)
134 IPC_MESSAGE_HANDLER(GpuMsg_GpuSwitched
, OnGpuSwitched
)
135 IPC_MESSAGE_UNHANDLED(handled
= false)
136 IPC_END_MESSAGE_MAP()
141 #if defined(USE_OZONE)
142 if (ui::OzonePlatform::GetInstance()
143 ->GetGpuPlatformSupport()
144 ->OnMessageReceived(msg
))
148 return gpu_channel_manager_
.get() &&
149 gpu_channel_manager_
->OnMessageReceived(msg
);
152 void GpuChildThread::OnInitialize() {
153 // Record initialization only after collecting the GPU info because that can
154 // take a significant amount of time.
155 gpu_info_
.initialization_time
= base::Time::Now() - process_start_time_
;
156 Send(new GpuHostMsg_Initialized(!dead_on_arrival_
, gpu_info_
));
157 while (!deferred_messages_
.empty()) {
158 Send(deferred_messages_
.front());
159 deferred_messages_
.pop();
162 if (dead_on_arrival_
) {
163 LOG(ERROR
) << "Exiting GPU process due to errors during initialization";
164 base::MessageLoop::current()->Quit();
168 #if defined(OS_ANDROID)
169 base::PlatformThread::SetThreadPriority(base::PlatformThread::CurrentHandle(),
170 base::ThreadPriority::DISPLAY
);
173 // We don't need to pipe log messages if we are running the GPU thread in
174 // the browser process.
175 if (!in_browser_process_
)
176 logging::SetLogMessageHandler(GpuProcessLogMessageHandler
);
178 // Defer creation of the render thread. This is to prevent it from handling
179 // IPC messages before the sandbox has been enabled and all other necessary
180 // initialization has succeeded.
181 gpu_channel_manager_
.reset(
182 new GpuChannelManager(GetRouter(),
183 watchdog_thread_
.get(),
184 ChildProcess::current()->io_message_loop_proxy(),
185 ChildProcess::current()->GetShutDownEvent(),
188 #if defined(USE_OZONE)
189 ui::OzonePlatform::GetInstance()
190 ->GetGpuPlatformSupport()
191 ->OnChannelEstablished(this);
195 void GpuChildThread::StopWatchdog() {
196 if (watchdog_thread_
.get()) {
197 watchdog_thread_
->Stop();
201 void GpuChildThread::OnCollectGraphicsInfo() {
203 // GPU full info collection should only happen on un-sandboxed GPU process
204 // or single process/in-process gpu mode on Windows.
205 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
206 DCHECK(command_line
->HasSwitch(switches::kDisableGpuSandbox
) ||
207 in_browser_process_
);
210 gpu::CollectInfoResult result
=
211 gpu::CollectContextGraphicsInfo(&gpu_info_
);
213 case gpu::kCollectInfoFatalFailure
:
214 LOG(ERROR
) << "gpu::CollectGraphicsInfo failed (fatal).";
215 // TODO(piman): can we signal overall failure?
217 case gpu::kCollectInfoNonFatalFailure
:
218 DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
220 case gpu::kCollectInfoNone
:
223 case gpu::kCollectInfoSuccess
:
226 GetContentClient()->SetGpuInfo(gpu_info_
);
229 // This is slow, but it's the only thing the unsandboxed GPU process does,
230 // and GpuDataManager prevents us from sending multiple collecting requests,
231 // so it's OK to be blocking.
232 gpu::GetDxDiagnostics(&gpu_info_
.dx_diagnostics
);
233 gpu_info_
.dx_diagnostics_info_state
= gpu::kCollectInfoSuccess
;
236 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_
));
239 if (!in_browser_process_
) {
240 // The unsandboxed GPU process fulfilled its duty. Rest in peace.
241 base::MessageLoop::current()->Quit();
246 void GpuChildThread::OnGetVideoMemoryUsageStats() {
247 GPUVideoMemoryUsageStats video_memory_usage_stats
;
248 if (gpu_channel_manager_
)
249 gpu_channel_manager_
->gpu_memory_manager()->GetVideoMemoryUsageStats(
250 &video_memory_usage_stats
);
251 Send(new GpuHostMsg_VideoMemoryUsageStats(video_memory_usage_stats
));
254 void GpuChildThread::OnClean() {
255 DVLOG(1) << "GPU: Removing all contexts";
256 if (gpu_channel_manager_
)
257 gpu_channel_manager_
->LoseAllContexts();
260 void GpuChildThread::OnCrash() {
261 DVLOG(1) << "GPU: Simulating GPU crash";
262 // Good bye, cruel world.
263 volatile int* it_s_the_end_of_the_world_as_we_know_it
= NULL
;
264 *it_s_the_end_of_the_world_as_we_know_it
= 0xdead;
267 void GpuChildThread::OnHang() {
268 DVLOG(1) << "GPU: Simulating GPU hang";
270 // Do not sleep here. The GPU watchdog timer tracks the amount of user
271 // time this thread is using and it doesn't use much while calling Sleep.
275 void GpuChildThread::OnDisableWatchdog() {
276 DVLOG(1) << "GPU: Disabling watchdog thread";
277 if (watchdog_thread_
.get()) {
278 // Disarm the watchdog before shutting down the message loop. This prevents
279 // the future posting of tasks to the message loop.
280 if (watchdog_thread_
->message_loop())
281 watchdog_thread_
->PostAcknowledge();
283 watchdog_thread_
->Stop();
287 void GpuChildThread::OnGpuSwitched() {
288 DVLOG(1) << "GPU: GPU has switched";
289 // Notify observers in the GPU process.
290 ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
293 } // namespace content