Home | History | Annotate | Download | only in gpu
      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 
    241