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 */ 11 cr.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 revision', 68 value: clientInfo.angle_revision 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 '3d_css': '3D CSS', 86 'css_animation': 'CSS Animation', 87 'compositing': 'Compositing', 88 'webgl': 'WebGL', 89 'multisampling': 'WebGL multisampling', 90 'flash_3d': 'Flash 3D', 91 'flash_stage3d': 'Flash Stage3D', 92 'flash_stage3d_baseline': 'Flash Stage3D Baseline profile', 93 'texture_sharing': 'Texture Sharing', 94 'video_decode': 'Video Decode', 95 'video_encode': 'Video Encode', 96 'video': 'Video', 97 // GPU Switching 98 'gpu_switching': 'GPU Switching', 99 'panel_fitting': 'Panel Fitting', 100 'force_compositing_mode': 'Force Compositing Mode', 101 'raster': 'Rasterization', 102 }; 103 var statusLabelMap = { 104 'disabled_software': 'Software only. Hardware acceleration disabled.', 105 'disabled_software_animated': 'Software animated.', 106 'disabled_off': 'Unavailable. Hardware acceleration disabled.', 107 'software': 'Software rendered. Hardware acceleration not enabled.', 108 'unavailable_off': 'Unavailable. Hardware acceleration unavailable', 109 'unavailable_software': 110 'Software only, hardware acceleration unavailable', 111 'enabled_readback': 'Hardware accelerated, but at reduced performance', 112 'enabled_force': 'Hardware accelerated on all pages', 113 'enabled_threaded': 'Hardware accelerated on demand and threaded', 114 'enabled_force_threaded': 115 'Hardware accelerated on all pages and threaded', 116 'enabled': 'Hardware accelerated', 117 'accelerated': 'Accelerated', 118 'accelerated_threaded': 'Accelerated and threaded', 119 // GPU Switching 120 'gpu_switching_automatic': 'Automatic switching', 121 'gpu_switching_force_discrete': 'Always on discrete GPU', 122 'gpu_switching_force_integrated': 'Always on integrated GPU', 123 'disabled_software_multithreaded': 'Software only, multi-threaded', 124 }; 125 126 var statusClassMap = { 127 'disabled_software': 'feature-yellow', 128 'disabled_software_animated': 'feature-yellow', 129 'disabled_off': 'feature-red', 130 'software': 'feature-yellow', 131 'unavailable_off': 'feature-red', 132 'unavailable_software': 'feature-yellow', 133 'enabled_force': 'feature-green', 134 'enabled_readback': 'feature-yellow', 135 'enabled_threaded': 'feature-green', 136 'enabled_force_threaded': 'feature-green', 137 'enabled': 'feature-green', 138 'accelerated': 'feature-green', 139 'accelerated_threaded': 'feature-green', 140 // GPU Switching 141 'gpu_switching_automatic': 'feature-green', 142 'gpu_switching_force_discrete': 'feature-red', 143 'gpu_switching_force_integrated': 'feature-red', 144 'disabled_software_multithreaded': 'feature-yellow', 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 if (!statusLabelMap[featureStatus]) 177 console.log('Missing statusLabel for', featureStatus); 178 if (!statusClassMap[featureStatus]) 179 console.log('Missing statusClass for', featureStatus); 180 statusEl.textContent = statusLabelMap[featureStatus]; 181 statusEl.className = statusClassMap[featureStatus]; 182 featureEl.appendChild(statusEl); 183 184 featureStatusList.appendChild(featureEl); 185 } 186 187 // problems list 188 if (gpuInfo.featureStatus.problems.length) { 189 problemsDiv.hidden = false; 190 problemsList.textContent = ''; 191 for (i = 0; i < gpuInfo.featureStatus.problems.length; i++) { 192 var problem = gpuInfo.featureStatus.problems[i]; 193 var problemEl = this.createProblemEl_(problem); 194 problemsList.appendChild(problemEl); 195 } 196 } else { 197 problemsDiv.hidden = true; 198 } 199 200 // driver bug workarounds list 201 if (gpuInfo.featureStatus.workarounds.length) { 202 workaroundsDiv.hidden = false; 203 workaroundsList.textContent = ''; 204 for (i = 0; i < gpuInfo.featureStatus.workarounds.length; i++) { 205 var workaroundEl = document.createElement('li'); 206 workaroundEl.textContent = gpuInfo.featureStatus.workarounds[i]; 207 workaroundsList.appendChild(workaroundEl); 208 } 209 } else { 210 workaroundsDiv.hidden = true; 211 } 212 213 } else { 214 featureStatusList.textContent = ''; 215 problemsList.hidden = true; 216 workaroundsList.hidden = true; 217 } 218 if (gpuInfo.basic_info) 219 this.setTable_('basic-info', gpuInfo.basic_info); 220 else 221 this.setTable_('basic-info', []); 222 223 if (gpuInfo.performance_info) { 224 performanceDiv.hidden = false; 225 this.setTable_('performance-info', gpuInfo.performance_info); 226 } else { 227 performanceDiv.hidden = true; 228 } 229 230 if (gpuInfo.diagnostics) { 231 diagnosticsDiv.hidden = false; 232 diagnosticsLoadingDiv.hidden = true; 233 $('diagnostics-table').hidden = false; 234 this.setTable_('diagnostics-table', gpuInfo.diagnostics); 235 } else if (gpuInfo.diagnostics === null) { 236 // gpu_internals.cc sets diagnostics to null when it is being loaded 237 diagnosticsDiv.hidden = false; 238 diagnosticsLoadingDiv.hidden = false; 239 $('diagnostics-table').hidden = true; 240 } else { 241 diagnosticsDiv.hidden = true; 242 } 243 } else { 244 this.setText_('basic-info', '... loading ...'); 245 diagnosticsDiv.hidden = true; 246 featureStatusList.textContent = ''; 247 problemsDiv.hidden = true; 248 } 249 250 // Log messages 251 jstProcess(new JsEvalContext({values: browserBridge.logMessages}), 252 $('log-messages')); 253 }, 254 255 createProblemEl_: function(problem) { 256 var problemEl; 257 problemEl = document.createElement('li'); 258 259 // Description of issue 260 var desc = document.createElement('a'); 261 desc.textContent = problem.description; 262 problemEl.appendChild(desc); 263 264 // Spacing ':' element 265 if (problem.crBugs.length + problem.webkitBugs.length > 0) { 266 var tmp = document.createElement('span'); 267 tmp.textContent = ': '; 268 problemEl.appendChild(tmp); 269 } 270 271 var nbugs = 0; 272 var j; 273 274 // crBugs 275 for (j = 0; j < problem.crBugs.length; ++j) { 276 if (nbugs > 0) { 277 var tmp = document.createElement('span'); 278 tmp.textContent = ', '; 279 problemEl.appendChild(tmp); 280 } 281 282 var link = document.createElement('a'); 283 var bugid = parseInt(problem.crBugs[j]); 284 link.textContent = bugid; 285 link.href = 'http://crbug.com/' + bugid; 286 problemEl.appendChild(link); 287 nbugs++; 288 } 289 290 for (j = 0; j < problem.webkitBugs.length; ++j) { 291 if (nbugs > 0) { 292 var tmp = document.createElement('span'); 293 tmp.textContent = ', '; 294 problemEl.appendChild(tmp); 295 } 296 297 var link = document.createElement('a'); 298 var bugid = parseInt(problem.webkitBugs[j]); 299 link.textContent = bugid; 300 301 link.href = 'https://bugs.webkit.org/show_bug.cgi?id=' + bugid; 302 problemEl.appendChild(link); 303 nbugs++; 304 } 305 306 return problemEl; 307 }, 308 309 setText_: function(outputElementId, text) { 310 var peg = document.getElementById(outputElementId); 311 peg.textContent = text; 312 }, 313 314 setTable_: function(outputElementId, inputData) { 315 var template = jstGetTemplate('info-view-table-template'); 316 jstProcess(new JsEvalContext({value: inputData}), 317 template); 318 319 var peg = document.getElementById(outputElementId); 320 if (!peg) 321 throw new Error('Node ' + outputElementId + ' not found'); 322 323 peg.innerHTML = ''; 324 peg.appendChild(template); 325 } 326 }; 327 328 return { 329 InfoView: InfoView 330 }; 331 }); 332