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 6/** 7 * @fileoverview This view displays information on the current GPU 8 * hardware. Its primary usefulness is to allow users to copy-paste 9 * their data in an easy to read format for bug reports. 10 */ 11cr.define('gpu', function() { 12 /** 13 * Provides information on the GPU process and underlying graphics hardware. 14 * @constructor 15 * @extends {cr.ui.TabPanel} 16 */ 17 var InfoView = cr.ui.define(cr.ui.TabPanel); 18 19 InfoView.prototype = { 20 __proto__: cr.ui.TabPanel.prototype, 21 22 decorate: function() { 23 cr.ui.TabPanel.prototype.decorate.apply(this); 24 25 browserBridge.addEventListener('gpuInfoUpdate', this.refresh.bind(this)); 26 browserBridge.addEventListener('logMessagesChange', 27 this.refresh.bind(this)); 28 browserBridge.addEventListener('clientInfoChange', 29 this.refresh.bind(this)); 30 this.refresh(); 31 }, 32 33 /** 34 * Updates the view based on its currently known data 35 */ 36 refresh: function(data) { 37 // Client info 38 if (browserBridge.clientInfo) { 39 var clientInfo = browserBridge.clientInfo; 40 41 var commandLineParts = clientInfo.command_line.split(' '); 42 commandLineParts.shift(); // Pop off the exe path 43 var commandLineString = commandLineParts.join(' ') 44 45 this.setTable_('client-info', [ 46 { 47 description: 'Data exported', 48 value: (new Date()).toLocaleString() 49 }, 50 { 51 description: 'Chrome version', 52 value: clientInfo.version 53 }, 54 { 55 description: 'Operating system', 56 value: clientInfo.operating_system 57 }, 58 { 59 description: 'Software rendering list version', 60 value: clientInfo.blacklist_version 61 }, 62 { 63 description: 'Driver bug list version', 64 value: clientInfo.driver_bug_list_version 65 }, 66 { 67 description: 'ANGLE commit id', 68 value: clientInfo.angle_commit_id 69 }, 70 { 71 description: '2D graphics backend', 72 value: clientInfo.graphics_backend 73 }, 74 { 75 description: 'Command Line Args', 76 value: commandLineString 77 }]); 78 } else { 79 this.setText_('client-info', '... loading...'); 80 } 81 82 // Feature map 83 var featureLabelMap = { 84 '2d_canvas': 'Canvas', 85 'gpu_compositing': 'Compositing', 86 'webgl': 'WebGL', 87 'multisampling': 'WebGL multisampling', 88 'flash_3d': 'Flash', 89 'flash_stage3d': 'Flash Stage3D', 90 'flash_stage3d_baseline': 'Flash Stage3D Baseline profile', 91 'texture_sharing': 'Texture Sharing', 92 'video_decode': 'Video Decode', 93 'video_encode': 'Video Encode', 94 'panel_fitting': 'Panel Fitting', 95 'rasterization': 'Rasterization', 96 'threaded_rasterization': 'Threaded Rasterization', 97 'multiple_raster_threads': 'Multiple Raster Threads', 98 }; 99 100 var statusMap = { 101 'disabled_software': { 102 'label': 'Software only. Hardware acceleration disabled', 103 'class': 'feature-yellow' 104 }, 105 'disabled_off': { 106 'label': 'Disabled', 107 'class': 'feature-red' 108 }, 109 'disabled_off_ok': { 110 'label': 'Disabled', 111 'class': 'feature-yellow' 112 }, 113 'unavailable_software': { 114 'label': 'Software only, hardware acceleration unavailable', 115 'class': 'feature-yellow' 116 }, 117 'unavailable_off': { 118 'label': 'Unavailable', 119 'class': 'feature-red' 120 }, 121 'unavailable_off_ok': { 122 'label': 'Unavailable', 123 'class': 'feature-yellow' 124 }, 125 'enabled_readback': { 126 'label': 'Hardware accelerated but at reduced performance', 127 'class': 'feature-yellow' 128 }, 129 'enabled_force': { 130 'label': 'Hardware accelerated on all pages', 131 'class': 'feature-green' 132 }, 133 'enabled': { 134 'label': 'Hardware accelerated', 135 'class': 'feature-green' 136 }, 137 'enabled_on': { 138 'label': 'Enabled', 139 'class': 'feature-green' 140 }, 141 'enabled_force_on': { 142 'label': 'Force enabled', 143 'class': 'feature-green' 144 }, 145 }; 146 147 // GPU info, basic 148 var diagnosticsDiv = this.querySelector('.diagnostics'); 149 var diagnosticsLoadingDiv = this.querySelector('.diagnostics-loading'); 150 var featureStatusList = this.querySelector('.feature-status-list'); 151 var problemsDiv = this.querySelector('.problems-div'); 152 var problemsList = this.querySelector('.problems-list'); 153 var workaroundsDiv = this.querySelector('.workarounds-div'); 154 var workaroundsList = this.querySelector('.workarounds-list'); 155 var performanceDiv = this.querySelector('.performance-div'); 156 var gpuInfo = browserBridge.gpuInfo; 157 var i; 158 if (gpuInfo) { 159 // Not using jstemplate here for blacklist status because we construct 160 // href from data, which jstemplate can't seem to do. 161 if (gpuInfo.featureStatus) { 162 // feature status list 163 featureStatusList.textContent = ''; 164 for (var featureName in gpuInfo.featureStatus.featureStatus) { 165 var featureStatus = 166 gpuInfo.featureStatus.featureStatus[featureName]; 167 var featureEl = document.createElement('li'); 168 169 var nameEl = document.createElement('span'); 170 if (!featureLabelMap[featureName]) 171 console.log('Missing featureLabel for', featureName); 172 nameEl.textContent = featureLabelMap[featureName] + ': '; 173 featureEl.appendChild(nameEl); 174 175 var statusEl = document.createElement('span'); 176 var statusInfo = statusMap[featureStatus]; 177 if (!statusInfo) { 178 console.log('Missing status for ', featureStatus); 179 statusEl.textContent = 'Unknown'; 180 statusEl.className = 'feature-red'; 181 } else { 182 statusEl.textContent = statusInfo['label']; 183 statusEl.className = statusInfo['class']; 184 } 185 featureEl.appendChild(statusEl); 186 187 featureStatusList.appendChild(featureEl); 188 } 189 190 // problems list 191 if (gpuInfo.featureStatus.problems.length) { 192 problemsDiv.hidden = false; 193 problemsList.textContent = ''; 194 for (i = 0; i < gpuInfo.featureStatus.problems.length; i++) { 195 var problem = gpuInfo.featureStatus.problems[i]; 196 var problemEl = this.createProblemEl_(problem); 197 problemsList.appendChild(problemEl); 198 } 199 } else { 200 problemsDiv.hidden = true; 201 } 202 203 // driver bug workarounds list 204 if (gpuInfo.featureStatus.workarounds.length) { 205 workaroundsDiv.hidden = false; 206 workaroundsList.textContent = ''; 207 for (i = 0; i < gpuInfo.featureStatus.workarounds.length; i++) { 208 var workaroundEl = document.createElement('li'); 209 workaroundEl.textContent = gpuInfo.featureStatus.workarounds[i]; 210 workaroundsList.appendChild(workaroundEl); 211 } 212 } else { 213 workaroundsDiv.hidden = true; 214 } 215 216 } else { 217 featureStatusList.textContent = ''; 218 problemsList.hidden = true; 219 workaroundsList.hidden = true; 220 } 221 if (gpuInfo.basic_info) 222 this.setTable_('basic-info', gpuInfo.basic_info); 223 else 224 this.setTable_('basic-info', []); 225 226 if (gpuInfo.performance_info) { 227 performanceDiv.hidden = false; 228 this.setTable_('performance-info', gpuInfo.performance_info); 229 } else { 230 performanceDiv.hidden = true; 231 } 232 233 if (gpuInfo.diagnostics) { 234 diagnosticsDiv.hidden = false; 235 diagnosticsLoadingDiv.hidden = true; 236 $('diagnostics-table').hidden = false; 237 this.setTable_('diagnostics-table', gpuInfo.diagnostics); 238 } else if (gpuInfo.diagnostics === null) { 239 // gpu_internals.cc sets diagnostics to null when it is being loaded 240 diagnosticsDiv.hidden = false; 241 diagnosticsLoadingDiv.hidden = false; 242 $('diagnostics-table').hidden = true; 243 } else { 244 diagnosticsDiv.hidden = true; 245 } 246 } else { 247 this.setText_('basic-info', '... loading ...'); 248 diagnosticsDiv.hidden = true; 249 featureStatusList.textContent = ''; 250 problemsDiv.hidden = true; 251 } 252 253 // Log messages 254 jstProcess(new JsEvalContext({values: browserBridge.logMessages}), 255 $('log-messages')); 256 }, 257 258 createProblemEl_: function(problem) { 259 var problemEl; 260 problemEl = document.createElement('li'); 261 262 // Description of issue 263 var desc = document.createElement('a'); 264 desc.textContent = problem.description; 265 problemEl.appendChild(desc); 266 267 // Spacing ':' element 268 if (problem.crBugs.length + problem.webkitBugs.length > 0) { 269 var tmp = document.createElement('span'); 270 tmp.textContent = ': '; 271 problemEl.appendChild(tmp); 272 } 273 274 var nbugs = 0; 275 var j; 276 277 // crBugs 278 for (j = 0; j < problem.crBugs.length; ++j) { 279 if (nbugs > 0) { 280 var tmp = document.createElement('span'); 281 tmp.textContent = ', '; 282 problemEl.appendChild(tmp); 283 } 284 285 var link = document.createElement('a'); 286 var bugid = parseInt(problem.crBugs[j]); 287 link.textContent = bugid; 288 link.href = 'http://crbug.com/' + bugid; 289 problemEl.appendChild(link); 290 nbugs++; 291 } 292 293 for (j = 0; j < problem.webkitBugs.length; ++j) { 294 if (nbugs > 0) { 295 var tmp = document.createElement('span'); 296 tmp.textContent = ', '; 297 problemEl.appendChild(tmp); 298 } 299 300 var link = document.createElement('a'); 301 var bugid = parseInt(problem.webkitBugs[j]); 302 link.textContent = bugid; 303 304 link.href = 'https://bugs.webkit.org/show_bug.cgi?id=' + bugid; 305 problemEl.appendChild(link); 306 nbugs++; 307 } 308 309 if (problem.affectedGpuSettings.length > 0) { 310 var brNode = document.createElement('br'); 311 problemEl.appendChild(brNode); 312 313 var iNode = document.createElement('i'); 314 problemEl.appendChild(iNode); 315 316 var headNode = document.createElement('span'); 317 if (problem.tag == 'disabledFeatures') 318 headNode.textContent = 'Disabled Features: '; 319 else // problem.tag == 'workarounds' 320 headNode.textContent = 'Applied Workarounds: '; 321 iNode.appendChild(headNode); 322 for (j = 0; j < problem.affectedGpuSettings.length; ++j) { 323 if (j > 0) { 324 var separateNode = document.createElement('span'); 325 separateNode.textContent = ', '; 326 iNode.appendChild(separateNode); 327 } 328 var nameNode = document.createElement('span'); 329 if (problem.tag == 'disabledFeatures') 330 nameNode.classList.add('feature-red'); 331 else // problem.tag == 'workarounds' 332 nameNode.classList.add('feature-yellow'); 333 nameNode.textContent = problem.affectedGpuSettings[j]; 334 iNode.appendChild(nameNode); 335 } 336 } 337 338 return problemEl; 339 }, 340 341 setText_: function(outputElementId, text) { 342 var peg = document.getElementById(outputElementId); 343 peg.textContent = text; 344 }, 345 346 setTable_: function(outputElementId, inputData) { 347 var template = jstGetTemplate('info-view-table-template'); 348 jstProcess(new JsEvalContext({value: inputData}), 349 template); 350 351 var peg = document.getElementById(outputElementId); 352 if (!peg) 353 throw new Error('Node ' + outputElementId + ' not found'); 354 355 peg.innerHTML = ''; 356 peg.appendChild(template); 357 } 358 }; 359 360 return { 361 InfoView: InfoView 362 }; 363}); 364