Skip to content
Snippets Groups Projects
Commit 41579aea authored by apatrick@chromium.org's avatar apatrick@chromium.org
Browse files

Collect DirectX diagnostic information asynchronously.

Collecting this can take a couple of seconds. I put the code onto a worker thread. The about:gpuinfo handler polls for it until it is available, initially displaying only the subset of informtation that can be retreived quickly.

This makes the startup time for accelerated compositing, WebGL, etc significantly lower on Windows. None of the other platforms have this issue.

TEST=go to about:gpuinfo, try
BUG=59711

Review URL: http://codereview.chromium.org/4860001

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66184 0039d316-1c4b-4281-b951-d872f2087c98
parent b7ba5b5e
No related merge requests found
......@@ -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;
}
......
......@@ -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)
......
......@@ -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_;
......
......@@ -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;
......
......@@ -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());
}
......@@ -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;
}
......
......@@ -163,6 +163,8 @@ bool CollectGraphicsInfo(GPUInfo* gpu_info) {
gl_version,
false);
gpu_info->SetProgress(GPUInfo::kComplete);
return true;
}
......
......@@ -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) {
......
......@@ -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
......@@ -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_;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment