Commit 4b7bb41a authored by Zhenyao Mo's avatar Zhenyao Mo Committed by Chromium LUCI CQ

Polish logic for displaying hardware GPU info on about:gpu

1) GPU switching is considered and this CL made sure the hardware
   GPU info displayed in the about:gpu is the last active GPU
   before Chrome falls back to SwiftShader.
2) Don't put SwiftShader info into hardware GPU section. Before
   this CL, if we run Chrome with GPU acceleration off, SwiftShader
   ended up in the hardware GPU section.

BUG=1154047
TEST=manual, gpu bots
R=kbr@chromium.org

Change-Id: I08ea41a25d40610e0d13da83f8b5dfeb50011b57
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2613741Reviewed-by: default avatarKenneth Russell <kbr@chromium.org>
Commit-Queue: Zhenyao Mo <zmo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841580}
parent 0408582f
......@@ -900,12 +900,44 @@ void GpuDataManagerImplPrivate::UpdateGpuInfo(
}
#endif // OS_WIN
if (!gpu_info_for_hardware_gpu_.IsInitialized()) {
if (gpu_info_for_hardware_gpu) {
bool needs_to_update_gpu_info_for_hardware_gpu =
!gpu_info_for_hardware_gpu_.IsInitialized();
if (!needs_to_update_gpu_info_for_hardware_gpu &&
!gpu_info_.UsesSwiftShader()) {
// On multi-GPU system, when switching to a different GPU, we want to reset
// GPUInfo for hardware GPU, because we want to know on which GPU Chrome
// crashes multiple times and falls back to SwiftShader.
const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info_.active_gpu();
const gpu::GPUInfo::GPUDevice& cached_active_gpu =
gpu_info_for_hardware_gpu_.active_gpu();
#if defined(OS_WIN)
if (active_gpu.luid.HighPart != cached_active_gpu.luid.HighPart &&
active_gpu.luid.LowPart != cached_active_gpu.luid.LowPart) {
needs_to_update_gpu_info_for_hardware_gpu = true;
}
#else
if (active_gpu.vendor_id != cached_active_gpu.vendor_id ||
active_gpu.device_id != cached_active_gpu.device_id) {
needs_to_update_gpu_info_for_hardware_gpu = true;
}
#endif // OS_WIN
}
if (needs_to_update_gpu_info_for_hardware_gpu) {
if (gpu_info_for_hardware_gpu.has_value()) {
DCHECK(gpu_info_for_hardware_gpu->IsInitialized());
gpu_info_for_hardware_gpu_ = gpu_info_for_hardware_gpu.value();
bool valid_info = true;
if (gpu_info_for_hardware_gpu->UsesSwiftShader()) {
valid_info = false;
} else if (gpu_info_for_hardware_gpu->gl_renderer.empty() &&
gpu_info_for_hardware_gpu->active_gpu().vendor_id == 0u) {
valid_info = false;
}
if (valid_info)
gpu_info_for_hardware_gpu_ = gpu_info_for_hardware_gpu.value();
} else {
gpu_info_for_hardware_gpu_ = gpu_info_;
if (!gpu_info_.UsesSwiftShader())
gpu_info_for_hardware_gpu_ = gpu_info_;
}
}
......
......@@ -865,28 +865,30 @@ void GpuMessageHandler::OnGpuInfoUpdate() {
feature_status->Set("workarounds", std::move(workarounds));
gpu_info_val->Set("featureStatus", std::move(feature_status));
if (!GpuDataManagerImpl::GetInstance()->IsGpuProcessUsingHardwareGpu()) {
auto feature_status_for_hardware_gpu =
std::make_unique<base::DictionaryValue>();
feature_status_for_hardware_gpu->Set("featureStatus",
GetFeatureStatusForHardwareGpu());
feature_status_for_hardware_gpu->Set("problems",
GetProblemsForHardwareGpu());
auto workarounds_for_hardware_gpu = std::make_unique<base::ListValue>();
for (const auto& workaround : GetDriverBugWorkaroundsForHardwareGpu())
workarounds_for_hardware_gpu->AppendString(workaround);
feature_status_for_hardware_gpu->Set(
"workarounds", std::move(workarounds_for_hardware_gpu));
gpu_info_val->Set("featureStatusForHardwareGpu",
std::move(feature_status_for_hardware_gpu));
const gpu::GPUInfo gpu_info_for_hardware_gpu =
GpuDataManagerImpl::GetInstance()->GetGPUInfoForHardwareGpu();
const gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu =
GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfoForHardwareGpu();
auto gpu_info_for_hardware_gpu_val = BasicGpuInfoAsListValue(
gpu_info_for_hardware_gpu, gpu_feature_info_for_hardware_gpu,
gfx::GpuExtraInfo{});
gpu_info_val->Set("basicInfoForHardwareGpu",
std::move(gpu_info_for_hardware_gpu_val));
if (gpu_info_for_hardware_gpu.IsInitialized()) {
auto feature_status_for_hardware_gpu =
std::make_unique<base::DictionaryValue>();
feature_status_for_hardware_gpu->Set("featureStatus",
GetFeatureStatusForHardwareGpu());
feature_status_for_hardware_gpu->Set("problems",
GetProblemsForHardwareGpu());
auto workarounds_for_hardware_gpu = std::make_unique<base::ListValue>();
for (const auto& workaround : GetDriverBugWorkaroundsForHardwareGpu())
workarounds_for_hardware_gpu->AppendString(workaround);
feature_status_for_hardware_gpu->Set(
"workarounds", std::move(workarounds_for_hardware_gpu));
gpu_info_val->Set("featureStatusForHardwareGpu",
std::move(feature_status_for_hardware_gpu));
const gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu =
GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfoForHardwareGpu();
auto gpu_info_for_hardware_gpu_val = BasicGpuInfoAsListValue(
gpu_info_for_hardware_gpu, gpu_feature_info_for_hardware_gpu,
gfx::GpuExtraInfo{});
gpu_info_val->Set("basicInfoForHardwareGpu",
std::move(gpu_info_for_hardware_gpu_val));
}
}
gpu_info_val->Set("compositorInfo", CompositorInfo());
gpu_info_val->Set("gpuMemoryBufferInfo", GpuMemoryBufferInfo(gpu_extra_info));
......
......@@ -28,7 +28,7 @@ startWebGLContext = function(opt_attrs) {
// Only continue if WebGL is available and working.
if (gl_context) {
gl_context.clearColor(0.0, 0.0, 0.0, 1.0);
gl_context.clearColor(0.0, 1.0, 0.0, 1.0);
gl_context.enable(gl_context.DEPTH_TEST);
gl_context.depthFunc(gl_context.LEQUAL);
gl_context.clearDepth(1);
......
<html>
<head>
<script type="text/javascript">
var gl_canvas;
var gl;
function onLoad() {
gl_canvas = document.getElementById("glcanvas");
gl_canvas.addEventListener("webglcontextlost", function(event) {
event.preventDefault();
}, false);
gl_canvas.addEventListener("webglcontextrestored", setupWebGL, false);
setupWebGL();
window.domAutomationController.reset = function() {
window.domAutomationController._loaded = false;
window.domAutomationController._succeeded = false;
window.domAutomationController._finished = false;
window.requestAnimationFrame(succeed);
};
window.domAutomationController.send("LOADED");
}
function setupWebGL() {
// Initialize the GL context.
gl = gl_canvas.getContext("webgl", {powerPreference: "high-performance"});
if (gl) {
gl.clearColor(0.0, 1.0, 0.0, 1.0);
gl.clearDepth(1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
}
function succeed() {
if (gl)
window.domAutomationController.send("SUCCESS");
}
</script>
</head>
<body onload="onLoad()">
<canvas id="glcanvas" width="640" height="480"></canvas>
</body>
</html>
......@@ -60,7 +60,7 @@ feature_query_script = """
} else {
query_result = document.querySelector('.feature-status-list');
}
for (let i=0; i < query_result.childElementCount; i++) {
for (let i = 0; i < query_result.childElementCount; i++) {
let feature_status = query_result.children[i].textContent.split(': ');
if (feature_status.length == 2 && feature_status[0] == feature_name)
return feature_status[1];
......@@ -69,6 +69,41 @@ feature_query_script = """
}
"""
vendor_id_query_script = """
function GetActiveVendorId(for_hardware_gpu) {
let div;
if (for_hardware_gpu) {
div = document.querySelector('.basic-info-for-hardware-gpu-div');
} else {
div = document.querySelector('#basic-info');
}
let trs = div.getElementsByTagName('tr');
let vendor_id = 0;
// The first four rows are "Initialization time", "In-process GPU",
// "Passthrough Command Decoder", and "Sandboxed".
for (let i = 4; i < trs.length; i++) {
let tds = trs[i].getElementsByTagName('td');
let token = tds[0].textContent.trim();
if (!token.startsWith('GPU'))
break;
if (i == 4 && token != 'GPU0')
break;
let gpu_string = tds[1].textContent.trim();
let vendor_info = gpu_string.split(', ')[0].split('= ');
if (vendor_info.length != 2 || vendor_info[0] != 'VENDOR')
break;
let id = parseInt(vendor_info[1]);
if (vendor_id == 0)
vendor_id = id;
if (gpu_string.endsWith('*ACTIVE*')) {
vendor_id = id;
break;
}
}
return vendor_id;
}
"""
class ContextLostIntegrationTest(gpu_integration_test.GpuIntegrationTest):
......@@ -140,7 +175,9 @@ class ContextLostIntegrationTest(gpu_integration_test.GpuIntegrationTest):
'webgl2-multisampling-high-power-switch-loses-context.html'),
('ContextLost_MacWebGLPreserveDBHighPowerSwitchLosesContext',
'webgl2-preserve-db-high-power-switch-loses-context.html'),
('GpuCrash_InfoForHardwareGpu', 'simple.html'))
('GpuCrash_InfoForHardwareGpu', 'simple.html'),
('GpuCrash_InfoForDualHardwareGpus', 'webgl-high-perf.html'))
for t in tests:
yield (t[0], t[1], ('_' + t[0]))
......@@ -255,6 +292,16 @@ class ContextLostIntegrationTest(gpu_integration_test.GpuIntegrationTest):
tab.Close()
return status
def _GetActiveVendorId(self, for_hardware_gpu):
tab = self.tab.browser.tabs.New()
tab.Navigate('chrome:gpu',
script_to_evaluate_on_commit=vendor_id_query_script)
tab.WaitForJavaScriptCondition('window.gpuPagePopulated', timeout=10)
vid = (tab.EvaluateJavaScript('GetActiveVendorId(%s)' %
('true' if for_hardware_gpu else 'false')))
tab.Close()
return vid
def _WaitForTabAndCheckCompletion(self):
tab = self.tab
completed = _WaitForPageToFinish(tab)
......@@ -501,6 +548,33 @@ class ContextLostIntegrationTest(gpu_integration_test.GpuIntegrationTest):
'but got %s' % webgl_status_for_hardware_gpu)
self._RestartBrowser('must restart after tests that kill the GPU process')
def _GpuCrash_InfoForDualHardwareGpus(self, test_path):
# Ensure that info displayed in chrome:gpu for hardware gpu is from
# the latest active GPU before the crash, after gpu process crashes three
# times and falls back to SwiftShader.
# Currently the test only works on Mac dual GPU bots.
if not self._IsDualGPUMacLaptop():
logging.info('Skipping test because not running on dual-GPU Mac laptop')
return
self.RestartBrowserIfNecessaryWithArgs(
[cba.DISABLE_DOMAIN_BLOCKING_FOR_3D_APIS])
active_vendor_id = self._GetActiveVendorId(False)
# Load WebGL content and switch to discrete GPU.
self._NavigateAndWaitForLoad(test_path)
new_active_vendor_id = self._GetActiveVendorId(False)
if not active_vendor_id or not new_active_vendor_id:
self.fail('Fail to query the active GPU vendor id from about:gpu')
# After three GPU crashes, check if the active vendor id for hardware GPU
# is the new_active_vendor_id.
self._KillGPUProcess(3, True)
active_vendor_id_for_hardware_gpu = self._GetActiveVendorId(True)
if not active_vendor_id_for_hardware_gpu:
self.fail('Fail to query the active GPU vendor id for hardware GPU')
if active_vendor_id_for_hardware_gpu != new_active_vendor_id:
self.fail('vendor id for hw GPU should be 0x%04x, got 0x%04x' %
(new_active_vendor_id, active_vendor_id_for_hardware_gpu))
self._RestartBrowser('must restart after tests that kill the GPU process')
@classmethod
def GetPlatformTags(cls, browser):
tags = super(ContextLostIntegrationTest, cls).GetPlatformTags(browser)
......
......@@ -136,3 +136,4 @@ crbug.com/1154047 [ fuchsia ] GpuCrash_InfoForHardwareGpu [ Skip ]
# Flaky hangs on Mac Debug NVIDIA, stalling the test suite for 40 minutes
crbug.com/1161570 [ mac nvidia debug ] GpuCrash_InfoForHardwareGpu [ Skip ]
crbug.com/1161570 [ mac nvidia debug ] GpuCrash_InfoForDualHardwareGpus [ Skip ]
......@@ -238,6 +238,10 @@ bool GPUInfo::IsInitialized() const {
return gpu.vendor_id != 0 || !gl_vendor.empty();
}
bool GPUInfo::UsesSwiftShader() const {
return gl_renderer.find("SwiftShader") != std::string::npos;
}
void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
struct GPUInfoKnownFields {
base::TimeDelta initialization_time;
......
......@@ -283,6 +283,8 @@ struct GPU_EXPORT GPUInfo {
bool IsInitialized() const;
bool UsesSwiftShader() const;
// The amount of time taken to get from the process starting to the message
// loop being pumped.
base::TimeDelta initialization_time;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment