Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / content / gpu / gpu_child_thread.cc
blob7cb56a7671566840f68b12c52c34dad1ed65e1b3
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_memory_buffer_factory.h"
14 #include "content/common/gpu/gpu_messages.h"
15 #include "content/gpu/gpu_watchdog_thread.h"
16 #include "content/public/common/content_client.h"
17 #include "content/public/common/content_switches.h"
18 #include "gpu/config/gpu_info_collector.h"
19 #include "ipc/ipc_channel_handle.h"
20 #include "ipc/ipc_sync_message_filter.h"
21 #include "ui/gl/gl_implementation.h"
22 #include "ui/gl/gpu_switching_manager.h"
24 #if defined(USE_OZONE)
25 #include "ui/ozone/public/gpu_platform_support.h"
26 #include "ui/ozone/public/ozone_platform.h"
27 #endif
29 namespace content {
30 namespace {
32 static base::LazyInstance<scoped_refptr<ThreadSafeSender> >
33 g_thread_safe_sender = LAZY_INSTANCE_INITIALIZER;
35 bool GpuProcessLogMessageHandler(int severity,
36 const char* file, int line,
37 size_t message_start,
38 const std::string& str) {
39 std::string header = str.substr(0, message_start);
40 std::string message = str.substr(message_start);
42 g_thread_safe_sender.Get()->Send(new GpuHostMsg_OnLogMessage(
43 severity, header, message));
45 return false;
48 // Message filter used to to handle GpuMsg_CreateGpuMemoryBuffer messages on
49 // the IO thread. This allows the UI thread in the browser process to remain
50 // fast at all times.
51 class GpuMemoryBufferMessageFilter : public IPC::MessageFilter {
52 public:
53 explicit GpuMemoryBufferMessageFilter(
54 GpuMemoryBufferFactory* gpu_memory_buffer_factory)
55 : gpu_memory_buffer_factory_(gpu_memory_buffer_factory),
56 sender_(nullptr) {}
58 // Overridden from IPC::MessageFilter:
59 void OnFilterAdded(IPC::Sender* sender) override {
60 DCHECK(!sender_);
61 sender_ = sender;
63 void OnFilterRemoved() override {
64 DCHECK(sender_);
65 sender_ = nullptr;
67 bool OnMessageReceived(const IPC::Message& message) override {
68 DCHECK(sender_);
69 bool handled = true;
70 IPC_BEGIN_MESSAGE_MAP(GpuMemoryBufferMessageFilter, message)
71 IPC_MESSAGE_HANDLER(GpuMsg_CreateGpuMemoryBuffer, OnCreateGpuMemoryBuffer)
72 IPC_MESSAGE_UNHANDLED(handled = false)
73 IPC_END_MESSAGE_MAP()
74 return handled;
77 protected:
78 ~GpuMemoryBufferMessageFilter() override {}
80 void OnCreateGpuMemoryBuffer(
81 const GpuMsg_CreateGpuMemoryBuffer_Params& params) {
82 TRACE_EVENT2("gpu", "GpuMemoryBufferMessageFilter::OnCreateGpuMemoryBuffer",
83 "id", params.id.id, "client_id", params.client_id);
84 sender_->Send(new GpuHostMsg_GpuMemoryBufferCreated(
85 gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(
86 params.id, params.size, params.format, params.usage,
87 params.client_id, params.surface_handle)));
90 GpuMemoryBufferFactory* const gpu_memory_buffer_factory_;
91 IPC::Sender* sender_;
94 ChildThreadImpl::Options GetOptions(
95 GpuMemoryBufferFactory* gpu_memory_buffer_factory) {
96 ChildThreadImpl::Options::Builder builder;
98 builder.AddStartupFilter(
99 new GpuMemoryBufferMessageFilter(gpu_memory_buffer_factory));
101 #if defined(USE_OZONE)
102 IPC::MessageFilter* message_filter = ui::OzonePlatform::GetInstance()
103 ->GetGpuPlatformSupport()
104 ->GetMessageFilter();
105 if (message_filter)
106 builder.AddStartupFilter(message_filter);
107 #endif
109 return builder.Build();
112 } // namespace
114 GpuChildThread::GpuChildThread(
115 GpuWatchdogThread* watchdog_thread,
116 bool dead_on_arrival,
117 const gpu::GPUInfo& gpu_info,
118 const DeferredMessages& deferred_messages,
119 GpuMemoryBufferFactory* gpu_memory_buffer_factory,
120 gpu::SyncPointManager* sync_point_manager)
121 : ChildThreadImpl(GetOptions(gpu_memory_buffer_factory)),
122 dead_on_arrival_(dead_on_arrival),
123 sync_point_manager_(sync_point_manager),
124 gpu_info_(gpu_info),
125 deferred_messages_(deferred_messages),
126 in_browser_process_(false),
127 gpu_memory_buffer_factory_(gpu_memory_buffer_factory) {
128 watchdog_thread_ = watchdog_thread;
129 #if defined(OS_WIN)
130 target_services_ = NULL;
131 #endif
132 g_thread_safe_sender.Get() = thread_safe_sender();
135 GpuChildThread::GpuChildThread(
136 const InProcessChildThreadParams& params,
137 GpuMemoryBufferFactory* gpu_memory_buffer_factory,
138 gpu::SyncPointManager* sync_point_manager)
139 : ChildThreadImpl(ChildThreadImpl::Options::Builder()
140 .InBrowserProcess(params)
141 .AddStartupFilter(new GpuMemoryBufferMessageFilter(
142 gpu_memory_buffer_factory))
143 .Build()),
144 dead_on_arrival_(false),
145 sync_point_manager_(sync_point_manager),
146 in_browser_process_(true),
147 gpu_memory_buffer_factory_(gpu_memory_buffer_factory) {
148 #if defined(OS_WIN)
149 target_services_ = NULL;
150 #endif
151 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
152 switches::kSingleProcess) ||
153 base::CommandLine::ForCurrentProcess()->HasSwitch(
154 switches::kInProcessGPU));
156 if (!gfx::GLSurface::InitializeOneOff())
157 VLOG(1) << "gfx::GLSurface::InitializeOneOff failed";
159 g_thread_safe_sender.Get() = thread_safe_sender();
162 GpuChildThread::~GpuChildThread() {
163 while (!deferred_messages_.empty()) {
164 delete deferred_messages_.front();
165 deferred_messages_.pop();
169 // static
170 gfx::GpuMemoryBufferType GpuChildThread::GetGpuMemoryBufferFactoryType() {
171 std::vector<gfx::GpuMemoryBufferType> supported_types;
172 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
173 DCHECK(!supported_types.empty());
174 // Note: We always use the preferred type.
175 return supported_types[0];
178 void GpuChildThread::Shutdown() {
179 ChildThreadImpl::Shutdown();
180 logging::SetLogMessageHandler(NULL);
183 void GpuChildThread::Init(const base::Time& process_start_time) {
184 process_start_time_ = process_start_time;
187 bool GpuChildThread::Send(IPC::Message* msg) {
188 // The GPU process must never send a synchronous IPC message to the browser
189 // process. This could result in deadlock.
190 DCHECK(!msg->is_sync());
192 return ChildThreadImpl::Send(msg);
195 bool GpuChildThread::OnControlMessageReceived(const IPC::Message& msg) {
196 bool handled = true;
197 IPC_BEGIN_MESSAGE_MAP(GpuChildThread, msg)
198 IPC_MESSAGE_HANDLER(GpuMsg_Initialize, OnInitialize)
199 IPC_MESSAGE_HANDLER(GpuMsg_Finalize, OnFinalize)
200 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo)
201 IPC_MESSAGE_HANDLER(GpuMsg_GetVideoMemoryUsageStats,
202 OnGetVideoMemoryUsageStats)
203 IPC_MESSAGE_HANDLER(GpuMsg_Clean, OnClean)
204 IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash)
205 IPC_MESSAGE_HANDLER(GpuMsg_Hang, OnHang)
206 IPC_MESSAGE_HANDLER(GpuMsg_DisableWatchdog, OnDisableWatchdog)
207 IPC_MESSAGE_HANDLER(GpuMsg_GpuSwitched, OnGpuSwitched)
208 IPC_MESSAGE_UNHANDLED(handled = false)
209 IPC_END_MESSAGE_MAP()
211 if (handled)
212 return true;
214 #if defined(USE_OZONE)
215 if (ui::OzonePlatform::GetInstance()
216 ->GetGpuPlatformSupport()
217 ->OnMessageReceived(msg))
218 return true;
219 #endif
221 return false;
224 bool GpuChildThread::OnMessageReceived(const IPC::Message& msg) {
225 if (ChildThreadImpl::OnMessageReceived(msg))
226 return true;
228 return gpu_channel_manager_.get() &&
229 gpu_channel_manager_->OnMessageReceived(msg);
232 void GpuChildThread::OnInitialize() {
233 // Record initialization only after collecting the GPU info because that can
234 // take a significant amount of time.
235 gpu_info_.initialization_time = base::Time::Now() - process_start_time_;
236 Send(new GpuHostMsg_Initialized(!dead_on_arrival_, gpu_info_));
237 while (!deferred_messages_.empty()) {
238 Send(deferred_messages_.front());
239 deferred_messages_.pop();
242 if (dead_on_arrival_) {
243 LOG(ERROR) << "Exiting GPU process due to errors during initialization";
244 base::MessageLoop::current()->Quit();
245 return;
248 #if defined(OS_ANDROID)
249 base::PlatformThread::SetCurrentThreadPriority(base::ThreadPriority::DISPLAY);
250 #endif
252 // We don't need to pipe log messages if we are running the GPU thread in
253 // the browser process.
254 if (!in_browser_process_)
255 logging::SetLogMessageHandler(GpuProcessLogMessageHandler);
257 // Defer creation of the render thread. This is to prevent it from handling
258 // IPC messages before the sandbox has been enabled and all other necessary
259 // initialization has succeeded.
260 gpu_channel_manager_.reset(new GpuChannelManager(
261 channel(), watchdog_thread_.get(),
262 base::ThreadTaskRunnerHandle::Get().get(),
263 ChildProcess::current()->io_task_runner(),
264 ChildProcess::current()->GetShutDownEvent(), GetAttachmentBroker(),
265 sync_point_manager_, gpu_memory_buffer_factory_));
267 #if defined(USE_OZONE)
268 ui::OzonePlatform::GetInstance()
269 ->GetGpuPlatformSupport()
270 ->OnChannelEstablished(this);
271 #endif
274 void GpuChildThread::OnFinalize() {
275 // Quit the GPU process
276 base::MessageLoop::current()->Quit();
279 void GpuChildThread::StopWatchdog() {
280 if (watchdog_thread_.get()) {
281 watchdog_thread_->Stop();
285 void GpuChildThread::OnCollectGraphicsInfo() {
286 #if defined(OS_WIN)
287 // GPU full info collection should only happen on un-sandboxed GPU process
288 // or single process/in-process gpu mode on Windows.
289 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
290 DCHECK(command_line->HasSwitch(switches::kDisableGpuSandbox) ||
291 in_browser_process_);
292 #endif // OS_WIN
294 gpu::CollectInfoResult result =
295 gpu::CollectContextGraphicsInfo(&gpu_info_);
296 switch (result) {
297 case gpu::kCollectInfoFatalFailure:
298 LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
299 // TODO(piman): can we signal overall failure?
300 break;
301 case gpu::kCollectInfoNonFatalFailure:
302 DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
303 break;
304 case gpu::kCollectInfoNone:
305 NOTREACHED();
306 break;
307 case gpu::kCollectInfoSuccess:
308 break;
310 GetContentClient()->SetGpuInfo(gpu_info_);
312 #if defined(OS_WIN)
313 // This is slow, but it's the only thing the unsandboxed GPU process does,
314 // and GpuDataManager prevents us from sending multiple collecting requests,
315 // so it's OK to be blocking.
316 gpu::GetDxDiagnostics(&gpu_info_.dx_diagnostics);
317 gpu_info_.dx_diagnostics_info_state = gpu::kCollectInfoSuccess;
318 #endif // OS_WIN
320 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_));
322 #if defined(OS_WIN)
323 if (!in_browser_process_) {
324 // The unsandboxed GPU process fulfilled its duty. Rest in peace.
325 base::MessageLoop::current()->Quit();
327 #endif // OS_WIN
330 void GpuChildThread::OnGetVideoMemoryUsageStats() {
331 GPUVideoMemoryUsageStats video_memory_usage_stats;
332 if (gpu_channel_manager_)
333 gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
334 &video_memory_usage_stats);
335 Send(new GpuHostMsg_VideoMemoryUsageStats(video_memory_usage_stats));
338 void GpuChildThread::OnClean() {
339 DVLOG(1) << "GPU: Removing all contexts";
340 if (gpu_channel_manager_)
341 gpu_channel_manager_->LoseAllContexts();
344 void GpuChildThread::OnCrash() {
345 DVLOG(1) << "GPU: Simulating GPU crash";
346 // Good bye, cruel world.
347 volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
348 *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
351 void GpuChildThread::OnHang() {
352 DVLOG(1) << "GPU: Simulating GPU hang";
353 for (;;) {
354 // Do not sleep here. The GPU watchdog timer tracks the amount of user
355 // time this thread is using and it doesn't use much while calling Sleep.
359 void GpuChildThread::OnDisableWatchdog() {
360 DVLOG(1) << "GPU: Disabling watchdog thread";
361 if (watchdog_thread_.get()) {
362 // Disarm the watchdog before shutting down the message loop. This prevents
363 // the future posting of tasks to the message loop.
364 if (watchdog_thread_->message_loop())
365 watchdog_thread_->PostAcknowledge();
366 // Prevent rearming.
367 watchdog_thread_->Stop();
371 void GpuChildThread::OnGpuSwitched() {
372 DVLOG(1) << "GPU: GPU has switched";
373 // Notify observers in the GPU process.
374 ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
377 } // namespace content