diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 79775e6f846c00f03ba977b8f9d2d16682ecb8dc..b63c88b9b49a857e27f959605d27c80b888ab6b1 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -761,18 +761,24 @@ std::string AboutGpu() {
   GPUInfo gpu_info = GpuProcessHost::Get()->gpu_info();
 
   std::string html;
-  if (!gpu_info.initialized()) {
+
+  html.append("<html><head><title>About GPU</title></head>\n");
+
+  if (gpu_info.progress() != GPUInfo::kComplete) {
     GpuProcessHostUIShim::Get()->CollectGraphicsInfoAsynchronously();
-    // If it's not initialized yet, let the user know and reload the page
-    html.append("<html><head><title>About GPU</title></head>\n");
+
+    // If it's not fully initialized yet, set a timeout to reload the page.
     html.append("<body onload=\"setTimeout('window.location.reload(true)',");
     html.append("2000)\">\n");
-    html.append("<h2>GPU Information</h2>\n");
+  } else {
+    html.append("<body>\n");
+  }
+
+  html.append("<h2>GPU Information</h2>\n");
+
+  if (gpu_info.progress() == GPUInfo::kUninitialized) {
     html.append("<p>Retrieving GPU information . . .</p>\n");
-    html.append("</body></html> ");
   } else {
-    html.append("<html><head><title>About GPU</title></head><body>\n");
-    html.append("<h2>GPU Information</h2>\n");
     html.append("<table><tr>");
     html.append("<td><strong>Initialization time</strong></td><td>");
     html.append(base::Int64ToString(
@@ -799,12 +805,17 @@ std::string AboutGpu() {
     html.append("</td></tr></table>");
 
 #if defined(OS_WIN)
-    html.append("<h2>DirectX Diagnostics</h2>");
-    DxDiagNodeToHTML(&html, gpu_info.dx_diagnostics());
+    if (gpu_info.progress() != GPUInfo::kComplete) {
+      html.append("<p>Retrieving DirectX Diagnostics . . .</p>\n");
+    } else {
+      html.append("<h2>DirectX Diagnostics</h2>");
+      DxDiagNodeToHTML(&html, gpu_info.dx_diagnostics());
+    }
 #endif
-
-    html.append("</body></html>");
   }
+
+  html.append("</body></html>");
+
   return html;
 }
 
diff --git a/chrome/common/gpu_info.cc b/chrome/common/gpu_info.cc
index 64f04985d038a5eb064c01f8fef8f1246a0c382b..744fdfcfc10a8be7d7a36efac3a7d6abba68a46d 100644
--- a/chrome/common/gpu_info.cc
+++ b/chrome/common/gpu_info.cc
@@ -5,15 +5,18 @@
 #include "chrome/common/gpu_info.h"
 
 GPUInfo::GPUInfo()
-    : initialized_(false), vendor_id_(0), device_id_(0), driver_version_(L""),
+    : progress_(kUninitialized),
+      vendor_id_(0),
+      device_id_(0),
+      driver_version_(L""),
       pixel_shader_version_(0),
       vertex_shader_version_(0),
       gl_version_(0),
       can_lose_context_(false) {
 }
 
-bool GPUInfo::initialized() const {
-  return initialized_;
+GPUInfo::Progress GPUInfo::progress() const {
+  return progress_;
 }
 
 base::TimeDelta GPUInfo::initialization_time() const {
@@ -68,7 +71,10 @@ void GPUInfo::SetGraphicsInfo(uint32 vendor_id, uint32 device_id,
   vertex_shader_version_ = vertex_shader_version;
   gl_version_ = gl_version;
   can_lose_context_ = can_lose_context;
-  initialized_ = true;
+}
+
+void GPUInfo::SetProgress(Progress progress) {
+  progress_ = progress;
 }
 
 #if defined(OS_WIN)
diff --git a/chrome/common/gpu_info.h b/chrome/common/gpu_info.h
index bdf8709ef62cb680c398821f43e78989595e472a..b8f7cc6261b3cdb7a3b801921e3dd6a80f9613b7 100644
--- a/chrome/common/gpu_info.h
+++ b/chrome/common/gpu_info.h
@@ -21,8 +21,15 @@ class GPUInfo {
   GPUInfo();
   ~GPUInfo() {}
 
-  // Returns whether this GPUInfo has been initialized with information
-  bool initialized() const;
+  enum Progress {
+    kUninitialized,
+    kPartial,
+    kComplete,
+  };
+
+  // Returns whether this GPUInfo has been partially or fully initialized with
+  // information.
+  Progress progress() const;
 
   // The amount of time taken to get from the process starting to the message
   // loop being pumped.
@@ -60,6 +67,8 @@ class GPUInfo {
   // semantics are available.
   bool can_lose_context() const;
 
+  void SetProgress(Progress progress);
+
   void SetInitializationTime(const base::TimeDelta& initialization_time);
 
   // Populate variables with passed in values
@@ -78,7 +87,7 @@ class GPUInfo {
 #endif
 
  private:
-  bool initialized_;
+  Progress progress_;
   base::TimeDelta initialization_time_;
   uint32 vendor_id_;
   uint32 device_id_;
diff --git a/chrome/common/gpu_messages.cc b/chrome/common/gpu_messages.cc
index d6adda01a5fbcfb17ab6be2a86d5e2a76547a949..1ba2efa3961b365d966bda7922930cd8dd0d336f 100644
--- a/chrome/common/gpu_messages.cc
+++ b/chrome/common/gpu_messages.cc
@@ -81,14 +81,15 @@ void ParamTraits<GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params> ::Log(
 #endif  // if defined(OS_MACOSX)
 
 void ParamTraits<GPUInfo> ::Write(Message* m, const param_type& p) {
-  ParamTraits<base::TimeDelta> ::Write(m, p.initialization_time());
-  m->WriteUInt32(p.vendor_id());
-  m->WriteUInt32(p.device_id());
-  m->WriteWString(p.driver_version());
-  m->WriteUInt32(p.pixel_shader_version());
-  m->WriteUInt32(p.vertex_shader_version());
-  m->WriteUInt32(p.gl_version());
-  m->WriteBool(p.can_lose_context());
+  WriteParam(m, static_cast<int32>(p.progress()));
+  WriteParam(m, p.initialization_time());
+  WriteParam(m, p.vendor_id());
+  WriteParam(m, p.device_id());
+  WriteParam(m, p.driver_version());
+  WriteParam(m, p.pixel_shader_version());
+  WriteParam(m, p.vertex_shader_version());
+  WriteParam(m, p.gl_version());
+  WriteParam(m, p.can_lose_context());
 
 #if defined(OS_WIN)
   ParamTraits<DxDiagNode> ::Write(m, p.dx_diagnostics());
@@ -96,6 +97,7 @@ void ParamTraits<GPUInfo> ::Write(Message* m, const param_type& p) {
 }
 
 bool ParamTraits<GPUInfo> ::Read(const Message* m, void** iter, param_type* p) {
+  int32 progress;
   base::TimeDelta initialization_time;
   uint32 vendor_id;
   uint32 device_id;
@@ -104,14 +106,16 @@ bool ParamTraits<GPUInfo> ::Read(const Message* m, void** iter, param_type* p) {
   uint32 vertex_shader_version;
   uint32 gl_version;
   bool can_lose_context;
-  bool ret = ParamTraits<base::TimeDelta> ::Read(m, iter, &initialization_time);
-  ret = ret && m->ReadUInt32(iter, &vendor_id);
-  ret = ret && m->ReadUInt32(iter, &device_id);
-  ret = ret && m->ReadWString(iter, &driver_version);
-  ret = ret && m->ReadUInt32(iter, &pixel_shader_version);
-  ret = ret && m->ReadUInt32(iter, &vertex_shader_version);
-  ret = ret && m->ReadUInt32(iter, &gl_version);
-  ret = ret && m->ReadBool(iter, &can_lose_context);
+  bool ret = ReadParam(m, iter, &progress);
+  ret = ret && ReadParam(m, iter, &initialization_time);
+  ret = ret && ReadParam(m, iter, &vendor_id);
+  ret = ret && ReadParam(m, iter, &device_id);
+  ret = ret && ReadParam(m, iter, &driver_version);
+  ret = ret && ReadParam(m, iter, &pixel_shader_version);
+  ret = ret && ReadParam(m, iter, &vertex_shader_version);
+  ret = ret && ReadParam(m, iter, &gl_version);
+  ret = ret && ReadParam(m, iter, &can_lose_context);
+  p->SetProgress(static_cast<GPUInfo::Progress>(progress));
   if (!ret)
     return false;
 
@@ -126,15 +130,18 @@ bool ParamTraits<GPUInfo> ::Read(const Message* m, void** iter, param_type* p) {
 
 #if defined(OS_WIN)
   DxDiagNode dx_diagnostics;
-  ret = ret && ParamTraits<DxDiagNode> ::Read(m, iter, &dx_diagnostics);
+  if (!ReadParam(m, iter, &dx_diagnostics))
+    return false;
+
   p->SetDxDiagnostics(dx_diagnostics);
 #endif
 
-  return ret;
+  return true;
 }
 
 void ParamTraits<GPUInfo> ::Log(const param_type& p, std::string* l) {
-  l->append(base::StringPrintf("<GPUInfo> %d %x %x %ls %d",
+  l->append(base::StringPrintf("<GPUInfo> %d %d %x %x %ls %d",
+                               p.progress(),
                                static_cast<int32>(
                                    p.initialization_time().InMilliseconds()),
                                p.vendor_id(),
@@ -144,21 +151,15 @@ void ParamTraits<GPUInfo> ::Log(const param_type& p, std::string* l) {
 }
 
 void ParamTraits<DxDiagNode> ::Write(Message* m, const param_type& p) {
-  ParamTraits<std::map<std::string, std::string> >::Write(m, p.values);
-  ParamTraits<std::map<std::string, DxDiagNode> >::Write(m, p.children);
+  WriteParam(m, p.values);
+  WriteParam(m, p.children);
 }
 
 bool ParamTraits<DxDiagNode> ::Read(const Message* m,
                                     void** iter,
                                     param_type* p) {
-  bool ret = ParamTraits<std::map<std::string, std::string> >::Read(
-      m,
-      iter,
-      &p->values);
-  ret = ret && ParamTraits<std::map<std::string, DxDiagNode> >::Read(
-      m,
-      iter,
-      &p->children);
+  bool ret = ReadParam(m, iter, &p->values);
+  ret = ret && ReadParam(m, iter, &p->children);
   return ret;
 }
 
@@ -168,22 +169,22 @@ void ParamTraits<DxDiagNode> ::Log(const param_type& p, std::string* l) {
 
 void ParamTraits<gpu::CommandBuffer::State> ::Write(Message* m,
                                                     const param_type& p) {
-  m->WriteInt(p.num_entries);
-  m->WriteInt(p.get_offset);
-  m->WriteInt(p.put_offset);
-  m->WriteInt(p.token);
-  m->WriteInt(p.error);
+  WriteParam(m, p.num_entries);
+  WriteParam(m, p.get_offset);
+  WriteParam(m, p.put_offset);
+  WriteParam(m, p.token);
+  WriteParam(m, static_cast<int32>(p.error));
 }
 
 bool ParamTraits<gpu::CommandBuffer::State> ::Read(const Message* m,
                                                    void** iter,
                                                    param_type* p) {
   int32 temp;
-  if (m->ReadInt(iter, &p->num_entries) &&
-      m->ReadInt(iter, &p->get_offset) &&
-      m->ReadInt(iter, &p->put_offset) &&
-      m->ReadInt(iter, &p->token) &&
-      m->ReadInt(iter, &temp)) {
+  if (ReadParam(m, iter, &p->num_entries) &&
+      ReadParam(m, iter, &p->get_offset) &&
+      ReadParam(m, iter, &p->put_offset) &&
+      ReadParam(m, iter, &p->token) &&
+      ReadParam(m, iter, &temp)) {
     p->error = static_cast<gpu::error::Error>(temp);
     return true;
   } else {
@@ -198,14 +199,14 @@ void ParamTraits<gpu::CommandBuffer::State> ::Log(const param_type& p,
 
 void ParamTraits<GPUCreateCommandBufferConfig> ::Write(
     Message* m, const param_type& p) {
-  m->WriteString(p.allowed_extensions);
-  ParamTraits<std::vector<int> > ::Write(m, p.attribs);
+  WriteParam(m, p.allowed_extensions);
+  WriteParam(m, p.attribs);
 }
 
 bool ParamTraits<GPUCreateCommandBufferConfig> ::Read(
     const Message* m, void** iter, param_type* p) {
-  if (!m->ReadString(iter, &p->allowed_extensions) ||
-      !ParamTraits<std::vector<int> > ::Read(m, iter, &p->attribs)) {
+  if (!ReadParam(m, iter, &p->allowed_extensions) ||
+      !ReadParam(m, iter, &p->attribs)) {
     return false;
   }
   return true;
diff --git a/chrome/common/gpu_messages_unittest.cc b/chrome/common/gpu_messages_unittest.cc
index 59d42edaf583c00f9e5d04014c37ee67cb750814..904d9dac26d3dd99f5bb3cd45b58c8b487992e16 100644
--- a/chrome/common/gpu_messages_unittest.cc
+++ b/chrome/common/gpu_messages_unittest.cc
@@ -13,6 +13,7 @@
 TEST(GPUIPCMessageTest, GPUInfo) {
   GPUInfo input;
   // Test variables taken from Lenovo T61
+  input.SetProgress(GPUInfo::kPartial);
   input.SetInitializationTime(base::TimeDelta::FromMilliseconds(100));
   input.SetGraphicsInfo(0x10de, 0x429, L"6.14.11.7715",
                         0xffff0300,
@@ -26,6 +27,7 @@ TEST(GPUIPCMessageTest, GPUInfo) {
   GPUInfo output;
   void* iter = NULL;
   EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+  EXPECT_EQ(input.progress(), output.progress());
   EXPECT_EQ(input.initialization_time().InMilliseconds(),
             output.initialization_time().InMilliseconds());
   EXPECT_EQ(input.vendor_id(), output.vendor_id());
@@ -38,5 +40,5 @@ TEST(GPUIPCMessageTest, GPUInfo) {
 
   std::string log_message;
   IPC::LogParam(output, &log_message);
-  EXPECT_STREQ("<GPUInfo> 100 10de 429 6.14.11.7715 1", log_message.c_str());
+  EXPECT_STREQ("<GPUInfo> 1 100 10de 429 6.14.11.7715 1", log_message.c_str());
 }
diff --git a/chrome/gpu/gpu_info_collector_linux.cc b/chrome/gpu/gpu_info_collector_linux.cc
index 2a4db9a89c266aed936644092e53715be4a0e8d8..fd48c83e8a282250986714a905c1c42a6f47d469 100644
--- a/chrome/gpu/gpu_info_collector_linux.cc
+++ b/chrome/gpu/gpu_info_collector_linux.cc
@@ -12,6 +12,9 @@ bool CollectGraphicsInfo(GPUInfo* gpu_info) {
   // on this platform in the future.
   // bool can_lose_context =
   //     gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2;
+
+  gpu_info->SetProgress(GPUInfo::kComplete);
+
   return true;
 }
 
diff --git a/chrome/gpu/gpu_info_collector_mac.mm b/chrome/gpu/gpu_info_collector_mac.mm
index 02c12b0dace236408f91ff056c655029e8ec4460..9da958c8eb1844e275eccd5785c96c07efc338aa 100644
--- a/chrome/gpu/gpu_info_collector_mac.mm
+++ b/chrome/gpu/gpu_info_collector_mac.mm
@@ -163,6 +163,8 @@ bool CollectGraphicsInfo(GPUInfo* gpu_info) {
                             gl_version,
                             false);
 
+  gpu_info->SetProgress(GPUInfo::kComplete);
+
   return true;
 }
 
diff --git a/chrome/gpu/gpu_info_collector_win.cc b/chrome/gpu/gpu_info_collector_win.cc
index b5d30b489fb152ad46e04676c56a831383e1ee51..f1ed1f80348dbefdace99dc8a4b95e73bac381ca 100644
--- a/chrome/gpu/gpu_info_collector_win.cc
+++ b/chrome/gpu/gpu_info_collector_win.cc
@@ -37,13 +37,14 @@ bool CollectGraphicsInfo(GPUInfo* gpu_info) {
   if (FAILED(device->GetDirect3D(&d3d)))
     return false;
 
-  // Don't fail if DirectX diagnostics are not available. Just leave the tree
-  // empty. The other GPU info is still valuable.
-  DxDiagNode dx_diagnostics;
-  if (GetDxDiagnostics(&dx_diagnostics))
-    gpu_info->SetDxDiagnostics(dx_diagnostics);
+  if (!CollectGraphicsInfoD3D(d3d, gpu_info))
+    return false;
+
+  // DirectX diagnostics are collected asynchronously because it takes a
+  // couple of seconds. Do not mark as complete until that is done.
+  gpu_info->SetProgress(GPUInfo::kPartial);
 
-  return CollectGraphicsInfoD3D(d3d, gpu_info);
+  return true;
 }
 
 bool CollectGraphicsInfoD3D(IDirect3D9* d3d, GPUInfo* gpu_info) {
diff --git a/chrome/gpu/gpu_thread.cc b/chrome/gpu/gpu_thread.cc
index 9dc57d8f3f496d0514a3156946ecdcf6ef581344..e278bec21ef52b0a4bd18385e11fdd9f3384aeab 100644
--- a/chrome/gpu/gpu_thread.cc
+++ b/chrome/gpu/gpu_thread.cc
@@ -9,6 +9,7 @@
 
 #include "app/gfx/gl/gl_context.h"
 #include "base/command_line.h"
+#include "base/worker_pool.h"
 #include "build/build_config.h"
 #include "chrome/common/child_process.h"
 #include "chrome/common/child_process_logging.h"
@@ -16,6 +17,10 @@
 #include "chrome/gpu/gpu_info_collector.h"
 #include "ipc/ipc_channel_handle.h"
 
+#if defined(OS_WIN)
+#include "app/win_util.h"
+#endif
+
 #if defined(TOOLKIT_USES_GTK)
 #include <gtk/gtk.h>
 #include "app/x11_util.h"
@@ -44,6 +49,18 @@ void GpuThread::Init(const base::Time& process_start_time) {
   gpu_info_collector::CollectGraphicsInfo(&gpu_info_);
   child_process_logging::SetGpuInfo(gpu_info_);
 
+#if defined(OS_WIN)
+  // Asynchronously collect the DirectX diagnostics because this can take a
+  // couple of seconds.
+  if (!WorkerPool::PostTask(
+      FROM_HERE,
+      NewRunnableFunction(&GpuThread::CollectDxDiagnostics, this),
+      true)) {
+    // Flag GPU info as complete if the DirectX diagnostics cannot be collected.
+    gpu_info_.SetProgress(GPUInfo::kComplete);
+  }
+#endif
+
   // Record initialization only after collecting the GPU info because that can
   // take a significant amount of time.
   gpu_info_.SetInitializationTime(base::Time::Now() - process_start_time);
@@ -118,3 +135,26 @@ void GpuThread::OnHang() {
   for (;;)
     PlatformThread::Sleep(1000);
 }
+
+#if defined(OS_WIN)
+
+// Runs on a worker thread. The GpuThread never terminates voluntarily so it is
+// safe to assume that its message loop is valid.
+void GpuThread::CollectDxDiagnostics(GpuThread* thread) {
+  win_util::ScopedCOMInitializer com_initializer;
+
+  DxDiagNode node;
+  gpu_info_collector::GetDxDiagnostics(&node);
+
+  thread->message_loop()->PostTask(
+      FROM_HERE,
+      NewRunnableFunction(&GpuThread::SetDxDiagnostics, thread, node));
+}
+
+// Runs on the GPU thread.
+void GpuThread::SetDxDiagnostics(GpuThread* thread, const DxDiagNode& node) {
+  thread->gpu_info_.SetDxDiagnostics(node);
+  thread->gpu_info_.SetProgress(GPUInfo::kComplete);
+}
+
+#endif
diff --git a/chrome/gpu/gpu_thread.h b/chrome/gpu/gpu_thread.h
index 56d4b43156cea5a93db8be78ac2ddb09e3c45ad4..275fa128ca84a8960ddc305bde29fd746f1b7ae2 100644
--- a/chrome/gpu/gpu_thread.h
+++ b/chrome/gpu/gpu_thread.h
@@ -38,6 +38,11 @@ class GpuThread : public ChildThread {
   void OnCrash();
   void OnHang();
 
+#if defined(OS_WIN)
+  static void CollectDxDiagnostics(GpuThread* thread);
+  static void SetDxDiagnostics(GpuThread* thread, const DxDiagNode& node);
+#endif
+
   typedef base::hash_map<int, scoped_refptr<GpuChannel> > GpuChannelMap;
   GpuChannelMap gpu_channels_;