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_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"
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
,
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
));
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
51 class GpuMemoryBufferMessageFilter
: public IPC::MessageFilter
{
53 explicit GpuMemoryBufferMessageFilter(
54 GpuMemoryBufferFactory
* gpu_memory_buffer_factory
)
55 : gpu_memory_buffer_factory_(gpu_memory_buffer_factory
),
58 // Overridden from IPC::MessageFilter:
59 void OnFilterAdded(IPC::Sender
* sender
) override
{
63 void OnFilterRemoved() override
{
67 bool OnMessageReceived(const IPC::Message
& message
) override
{
70 IPC_BEGIN_MESSAGE_MAP(GpuMemoryBufferMessageFilter
, message
)
71 IPC_MESSAGE_HANDLER(GpuMsg_CreateGpuMemoryBuffer
, OnCreateGpuMemoryBuffer
)
72 IPC_MESSAGE_UNHANDLED(handled
= false)
78 ~GpuMemoryBufferMessageFilter() override
{}
80 void OnCreateGpuMemoryBuffer(
81 const GpuMsg_CreateGpuMemoryBuffer_Params
& params
) {
82 TRACE_EVENT2("gpu", "GpuMemoryBufferMessageFilter::OnCreateGpuMemoryBuffer",
83 "id", params
.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_
;
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();
106 builder
.AddStartupFilter(message_filter
);
109 return builder
.Build();
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
),
125 deferred_messages_(deferred_messages
),
126 in_browser_process_(false),
127 gpu_memory_buffer_factory_(gpu_memory_buffer_factory
) {
128 watchdog_thread_
= watchdog_thread
;
130 target_services_
= NULL
;
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
))
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
) {
149 target_services_
= NULL
;
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() {
166 gfx::GpuMemoryBufferType
GpuChildThread::GetGpuMemoryBufferFactoryType() {
167 std::vector
<gfx::GpuMemoryBufferType
> supported_types
;
168 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types
);
169 DCHECK(!supported_types
.empty());
170 // Note: We always use the preferred type.
171 return supported_types
[0];
174 void GpuChildThread::Shutdown() {
175 ChildThreadImpl::Shutdown();
176 logging::SetLogMessageHandler(NULL
);
179 void GpuChildThread::Init(const base::Time
& process_start_time
) {
180 process_start_time_
= process_start_time
;
183 bool GpuChildThread::Send(IPC::Message
* msg
) {
184 // The GPU process must never send a synchronous IPC message to the browser
185 // process. This could result in deadlock.
186 DCHECK(!msg
->is_sync());
188 return ChildThreadImpl::Send(msg
);
191 bool GpuChildThread::OnControlMessageReceived(const IPC::Message
& msg
) {
193 IPC_BEGIN_MESSAGE_MAP(GpuChildThread
, msg
)
194 IPC_MESSAGE_HANDLER(GpuMsg_Initialize
, OnInitialize
)
195 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo
, OnCollectGraphicsInfo
)
196 IPC_MESSAGE_HANDLER(GpuMsg_GetVideoMemoryUsageStats
,
197 OnGetVideoMemoryUsageStats
)
198 IPC_MESSAGE_HANDLER(GpuMsg_Clean
, OnClean
)
199 IPC_MESSAGE_HANDLER(GpuMsg_Crash
, OnCrash
)
200 IPC_MESSAGE_HANDLER(GpuMsg_Hang
, OnHang
)
201 IPC_MESSAGE_HANDLER(GpuMsg_DisableWatchdog
, OnDisableWatchdog
)
202 IPC_MESSAGE_HANDLER(GpuMsg_GpuSwitched
, OnGpuSwitched
)
203 IPC_MESSAGE_UNHANDLED(handled
= false)
204 IPC_END_MESSAGE_MAP()
209 #if defined(USE_OZONE)
210 if (ui::OzonePlatform::GetInstance()
211 ->GetGpuPlatformSupport()
212 ->OnMessageReceived(msg
))
216 return gpu_channel_manager_
.get() &&
217 gpu_channel_manager_
->OnMessageReceived(msg
);
220 void GpuChildThread::OnInitialize() {
221 // Record initialization only after collecting the GPU info because that can
222 // take a significant amount of time.
223 gpu_info_
.initialization_time
= base::Time::Now() - process_start_time_
;
224 Send(new GpuHostMsg_Initialized(!dead_on_arrival_
, gpu_info_
));
225 while (!deferred_messages_
.empty()) {
226 Send(deferred_messages_
.front());
227 deferred_messages_
.pop();
230 if (dead_on_arrival_
) {
231 LOG(ERROR
) << "Exiting GPU process due to errors during initialization";
232 base::MessageLoop::current()->Quit();
236 #if defined(OS_ANDROID)
237 base::PlatformThread::SetCurrentThreadPriority(base::ThreadPriority::DISPLAY
);
240 // We don't need to pipe log messages if we are running the GPU thread in
241 // the browser process.
242 if (!in_browser_process_
)
243 logging::SetLogMessageHandler(GpuProcessLogMessageHandler
);
245 // Defer creation of the render thread. This is to prevent it from handling
246 // IPC messages before the sandbox has been enabled and all other necessary
247 // initialization has succeeded.
248 gpu_channel_manager_
.reset(new GpuChannelManager(
249 GetRouter(), watchdog_thread_
.get(),
250 ChildProcess::current()->io_task_runner(),
251 ChildProcess::current()->GetShutDownEvent(), channel(),
252 GetAttachmentBroker(), sync_point_manager_
,
253 gpu_memory_buffer_factory_
));
255 #if defined(USE_OZONE)
256 ui::OzonePlatform::GetInstance()
257 ->GetGpuPlatformSupport()
258 ->OnChannelEstablished(this);
262 void GpuChildThread::StopWatchdog() {
263 if (watchdog_thread_
.get()) {
264 watchdog_thread_
->Stop();
268 void GpuChildThread::OnCollectGraphicsInfo() {
270 // GPU full info collection should only happen on un-sandboxed GPU process
271 // or single process/in-process gpu mode on Windows.
272 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
273 DCHECK(command_line
->HasSwitch(switches::kDisableGpuSandbox
) ||
274 in_browser_process_
);
277 gpu::CollectInfoResult result
=
278 gpu::CollectContextGraphicsInfo(&gpu_info_
);
280 case gpu::kCollectInfoFatalFailure
:
281 LOG(ERROR
) << "gpu::CollectGraphicsInfo failed (fatal).";
282 // TODO(piman): can we signal overall failure?
284 case gpu::kCollectInfoNonFatalFailure
:
285 DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
287 case gpu::kCollectInfoNone
:
290 case gpu::kCollectInfoSuccess
:
293 GetContentClient()->SetGpuInfo(gpu_info_
);
296 // This is slow, but it's the only thing the unsandboxed GPU process does,
297 // and GpuDataManager prevents us from sending multiple collecting requests,
298 // so it's OK to be blocking.
299 gpu::GetDxDiagnostics(&gpu_info_
.dx_diagnostics
);
300 gpu_info_
.dx_diagnostics_info_state
= gpu::kCollectInfoSuccess
;
303 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_
));
306 if (!in_browser_process_
) {
307 // The unsandboxed GPU process fulfilled its duty. Rest in peace.
308 base::MessageLoop::current()->Quit();
313 void GpuChildThread::OnGetVideoMemoryUsageStats() {
314 GPUVideoMemoryUsageStats video_memory_usage_stats
;
315 if (gpu_channel_manager_
)
316 gpu_channel_manager_
->gpu_memory_manager()->GetVideoMemoryUsageStats(
317 &video_memory_usage_stats
);
318 Send(new GpuHostMsg_VideoMemoryUsageStats(video_memory_usage_stats
));
321 void GpuChildThread::OnClean() {
322 DVLOG(1) << "GPU: Removing all contexts";
323 if (gpu_channel_manager_
)
324 gpu_channel_manager_
->LoseAllContexts();
327 void GpuChildThread::OnCrash() {
328 DVLOG(1) << "GPU: Simulating GPU crash";
329 // Good bye, cruel world.
330 volatile int* it_s_the_end_of_the_world_as_we_know_it
= NULL
;
331 *it_s_the_end_of_the_world_as_we_know_it
= 0xdead;
334 void GpuChildThread::OnHang() {
335 DVLOG(1) << "GPU: Simulating GPU hang";
337 // Do not sleep here. The GPU watchdog timer tracks the amount of user
338 // time this thread is using and it doesn't use much while calling Sleep.
342 void GpuChildThread::OnDisableWatchdog() {
343 DVLOG(1) << "GPU: Disabling watchdog thread";
344 if (watchdog_thread_
.get()) {
345 // Disarm the watchdog before shutting down the message loop. This prevents
346 // the future posting of tasks to the message loop.
347 if (watchdog_thread_
->message_loop())
348 watchdog_thread_
->PostAcknowledge();
350 watchdog_thread_
->Stop();
354 void GpuChildThread::OnGpuSwitched() {
355 DVLOG(1) << "GPU: GPU has switched";
356 // Notify observers in the GPU process.
357 ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
360 } // namespace content