- add sources.
[platform/framework/web/crosswalk.git] / src / content / gpu / gpu_child_thread.cc
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.
4
5 #include "content/gpu/gpu_child_thread.h"
6
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
22 namespace content {
23 namespace {
24
25 static base::LazyInstance<scoped_refptr<ThreadSafeSender> >
26     g_thread_safe_sender = LAZY_INSTANCE_INITIALIZER;
27
28 bool GpuProcessLogMessageHandler(int severity,
29                                  const char* file, int line,
30                                  size_t message_start,
31                                  const std::string& str) {
32   std::string header = str.substr(0, message_start);
33   std::string message = str.substr(message_start);
34
35   g_thread_safe_sender.Get()->Send(new GpuHostMsg_OnLogMessage(
36       severity, header, message));
37
38   return false;
39 }
40
41 }  // namespace
42
43 GpuChildThread::GpuChildThread(GpuWatchdogThread* watchdog_thread,
44                                bool dead_on_arrival,
45                                const gpu::GPUInfo& gpu_info,
46                                const DeferredMessages& deferred_messages)
47     : dead_on_arrival_(dead_on_arrival),
48       gpu_info_(gpu_info),
49       deferred_messages_(deferred_messages),
50       in_browser_process_(false) {
51   watchdog_thread_ = watchdog_thread;
52 #if defined(OS_WIN)
53   target_services_ = NULL;
54 #endif
55   g_thread_safe_sender.Get() = thread_safe_sender();
56 }
57
58 GpuChildThread::GpuChildThread(const std::string& channel_id)
59     : ChildThread(channel_id),
60       dead_on_arrival_(false),
61       in_browser_process_(true) {
62 #if defined(OS_WIN)
63   target_services_ = NULL;
64 #endif
65   DCHECK(
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()";
72   }
73   g_thread_safe_sender.Get() = thread_safe_sender();
74 }
75
76 GpuChildThread::~GpuChildThread() {
77 }
78
79 void GpuChildThread::Shutdown() {
80   ChildThread::Shutdown();
81   logging::SetLogMessageHandler(NULL);
82 }
83
84 void GpuChildThread::Init(const base::Time& process_start_time) {
85   process_start_time_ = process_start_time;
86 }
87
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());
92
93   return ChildThread::Send(msg);
94 }
95
96 bool GpuChildThread::OnControlMessageReceived(const IPC::Message& msg) {
97   bool msg_is_ok = true;
98   bool handled = 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()
110
111   if (handled)
112     return true;
113
114   return gpu_channel_manager_.get() &&
115       gpu_channel_manager_->OnMessageReceived(msg);
116 }
117
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();
123   }
124
125   if (dead_on_arrival_) {
126     VLOG(1) << "Exiting GPU process due to errors during initialization";
127     base::MessageLoop::current()->Quit();
128     return;
129   }
130
131 #if defined(OS_ANDROID)
132   base::PlatformThread::SetThreadPriority(
133       base::PlatformThread::CurrentHandle(),
134       base::kThreadPriority_Display);
135 #endif
136
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);
141
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_;
145
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()));
154
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_));
159 }
160
161 void GpuChildThread::StopWatchdog() {
162   if (watchdog_thread_.get()) {
163     watchdog_thread_->Stop();
164   }
165 }
166
167 void GpuChildThread::OnCollectGraphicsInfo() {
168 #if defined(OS_WIN)
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_);
174 #endif  // OS_WIN
175
176   if (!gpu::CollectContextGraphicsInfo(&gpu_info_))
177     VLOG(1) << "gpu::CollectGraphicsInfo failed";
178   GetContentClient()->SetGpuInfo(gpu_info_);
179
180 #if defined(OS_WIN)
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;
186 #endif  // OS_WIN
187
188   Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_));
189
190 #if defined(OS_WIN)
191   if (!in_browser_process_) {
192     // The unsandboxed GPU process fulfilled its duty.  Rest in peace.
193     base::MessageLoop::current()->Quit();
194   }
195 #endif  // OS_WIN
196 }
197
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));
204 }
205
206 void GpuChildThread::OnClean() {
207   VLOG(1) << "GPU: Removing all contexts";
208   if (gpu_channel_manager_)
209     gpu_channel_manager_->LoseAllContexts();
210 }
211
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;
217 }
218
219 void GpuChildThread::OnHang() {
220   VLOG(1) << "GPU: Simulating GPU hang";
221   for (;;) {
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.
224   }
225 }
226
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();
234     // Prevent rearming.
235     watchdog_thread_->Stop();
236   }
237 }
238
239 }  // namespace content
240