1<!DOCTYPE html> 2<!-- 3Copyright (c) 2013 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7 8<link rel="stylesheet" href="/tracing/ui/extras/chrome/cc/layer_picker.css"> 9 10<link rel="import" href="/tracing/extras/chrome/cc/constants.html"> 11<link rel="import" href="/tracing/extras/chrome/cc/layer_tree_host_impl.html"> 12<link rel="import" href="/tracing/extras/chrome/cc/util.html"> 13<link rel="import" href="/tracing/ui/analysis/generic_object_view.html"> 14<link rel="import" href="/tracing/model/event.html"> 15<link rel="import" href="/tracing/ui/base/drag_handle.html"> 16<link rel="import" href="/tracing/ui/base/list_view.html"> 17<link rel="import" href="/tracing/ui/base/dom_helpers.html"> 18<link rel="import" href="/tracing/ui/extras/chrome/cc/selection.html"> 19 20<script> 21'use strict'; 22 23tr.exportTo('tr.ui.e.chrome.cc', function() { 24 var constants = tr.e.cc.constants; 25 var bytesToRoundedMegabytes = tr.e.cc.bytesToRoundedMegabytes; 26 var RENDER_PASS_QUADS = 27 Math.max(constants.ACTIVE_TREE, constants.PENDING_TREE) + 1; 28 29 /** 30 * @constructor 31 */ 32 var LayerPicker = tr.ui.b.define('tr-ui-e-chrome-cc-layer-picker'); 33 34 LayerPicker.prototype = { 35 __proto__: HTMLUnknownElement.prototype, 36 37 decorate: function() { 38 this.lthi_ = undefined; 39 this.controls_ = document.createElement('top-controls'); 40 this.renderPassQuads_ = false; 41 42 43 this.itemList_ = new tr.ui.b.ListView(); 44 this.appendChild(this.controls_); 45 46 this.appendChild(this.itemList_); 47 48 this.itemList_.addEventListener( 49 'selection-changed', this.onItemSelectionChanged_.bind(this)); 50 51 this.controls_.appendChild(tr.ui.b.createSelector( 52 this, 'whichTree', 53 'layerPicker.whichTree', constants.ACTIVE_TREE, 54 [{label: 'Active tree', value: constants.ACTIVE_TREE}, 55 {label: 'Pending tree', value: constants.PENDING_TREE}, 56 {label: 'Render pass quads', value: RENDER_PASS_QUADS}])); 57 58 this.showPureTransformLayers_ = false; 59 var showPureTransformLayers = tr.ui.b.createCheckBox( 60 this, 'showPureTransformLayers', 61 'layerPicker.showPureTransformLayers', false, 62 'Transform layers'); 63 showPureTransformLayers.classList.add('show-transform-layers'); 64 showPureTransformLayers.title = 65 'When checked, pure transform layers are shown'; 66 this.controls_.appendChild(showPureTransformLayers); 67 }, 68 69 get lthiSnapshot() { 70 return this.lthiSnapshot_; 71 }, 72 73 set lthiSnapshot(lthiSnapshot) { 74 this.lthiSnapshot_ = lthiSnapshot; 75 this.updateContents_(); 76 }, 77 78 get whichTree() { 79 return this.renderPassQuads_ ? constants.ACTIVE_TREE : this.whichTree_; 80 }, 81 82 set whichTree(whichTree) { 83 this.whichTree_ = whichTree; 84 this.renderPassQuads_ = (whichTree == RENDER_PASS_QUADS); 85 this.updateContents_(); 86 tr.b.dispatchSimpleEvent(this, 'selection-change', false); 87 }, 88 89 get layerTreeImpl() { 90 if (this.lthiSnapshot === undefined) 91 return undefined; 92 return this.lthiSnapshot.getTree(this.whichTree); 93 }, 94 95 get isRenderPassQuads() { 96 return this.renderPassQuads_; 97 }, 98 99 get showPureTransformLayers() { 100 return this.showPureTransformLayers_; 101 }, 102 103 set showPureTransformLayers(show) { 104 if (this.showPureTransformLayers_ === show) 105 return; 106 this.showPureTransformLayers_ = show; 107 this.updateContents_(); 108 }, 109 110 getRenderPassInfos_: function() { 111 if (!this.lthiSnapshot_) 112 return []; 113 114 var renderPassInfo = []; 115 if (!this.lthiSnapshot_.args.frame || 116 !this.lthiSnapshot_.args.frame.renderPasses) 117 return renderPassInfo; 118 119 var renderPasses = this.lthiSnapshot_.args.frame.renderPasses; 120 for (var i = 0; i < renderPasses.length; ++i) { 121 var info = {renderPass: renderPasses[i], 122 depth: 0, 123 id: i, 124 name: 'cc::RenderPass'}; 125 renderPassInfo.push(info); 126 } 127 return renderPassInfo; 128 }, 129 130 getLayerInfos_: function() { 131 if (!this.lthiSnapshot_) 132 return []; 133 134 var tree = this.lthiSnapshot_.getTree(this.whichTree_); 135 if (!tree) 136 return []; 137 138 var layerInfos = []; 139 140 var showPureTransformLayers = this.showPureTransformLayers_; 141 142 function isPureTransformLayer(layer) { 143 if (layer.args.compositingReasons && 144 layer.args.compositingReasons.length != 1 && 145 layer.args.compositingReasons[0] != 'No reasons given') 146 return false; 147 148 if (layer.args.drawsContent) 149 return false; 150 151 return true; 152 } 153 var visitedLayers = {}; 154 function visitLayer(layer, depth, isMask, isReplica) { 155 if (visitedLayers[layer.layerId]) 156 return; 157 visitedLayers[layer.layerId] = true; 158 var info = {layer: layer, 159 depth: depth}; 160 161 if (layer.args.drawsContent) 162 info.name = layer.objectInstance.name; 163 else 164 info.name = 'cc::LayerImpl'; 165 166 if (layer.usingGpuRasterization) 167 info.name += ' (G)'; 168 169 info.isMaskLayer = isMask; 170 info.replicaLayer = isReplica; 171 172 if (showPureTransformLayers || !isPureTransformLayer(layer)) 173 layerInfos.push(info); 174 175 }; 176 tree.iterLayers(visitLayer); 177 return layerInfos; 178 }, 179 180 updateContents_: function() { 181 if (this.renderPassQuads_) 182 this.updateRenderPassContents_(); 183 else 184 this.updateLayerContents_(); 185 }, 186 187 updateRenderPassContents_: function() { 188 this.itemList_.clear(); 189 190 var selectedRenderPassId; 191 if (this.selection_ && this.selection_.associatedRenderPassId) 192 selectedRenderPassId = this.selection_.associatedRenderPassId; 193 194 var renderPassInfos = this.getRenderPassInfos_(); 195 renderPassInfos.forEach(function(renderPassInfo) { 196 var renderPass = renderPassInfo.renderPass; 197 var id = renderPassInfo.id; 198 199 var item = this.createElementWithDepth_(renderPassInfo.depth); 200 var labelEl = item.appendChild(tr.ui.b.createSpan()); 201 202 labelEl.textContent = renderPassInfo.name + ' ' + id; 203 item.renderPass = renderPass; 204 item.renderPassId = id; 205 this.itemList_.appendChild(item); 206 207 if (id == selectedRenderPassId) { 208 renderPass.selectionState = 209 tr.model.SelectionState.SELECTED; 210 } 211 }, this); 212 }, 213 214 updateLayerContents_: function() { 215 this.changingItemSelection_ = true; 216 try { 217 this.itemList_.clear(); 218 219 var selectedLayerId; 220 if (this.selection_ && this.selection_.associatedLayerId) 221 selectedLayerId = this.selection_.associatedLayerId; 222 223 var layerInfos = this.getLayerInfos_(); 224 layerInfos.forEach(function(layerInfo) { 225 var layer = layerInfo.layer; 226 var id = layer.layerId; 227 228 var item = this.createElementWithDepth_(layerInfo.depth); 229 var labelEl = item.appendChild(tr.ui.b.createSpan()); 230 231 labelEl.textContent = layerInfo.name + ' ' + id; 232 233 var notesEl = item.appendChild(tr.ui.b.createSpan()); 234 if (layerInfo.isMaskLayer) 235 notesEl.textContent += '(mask)'; 236 if (layerInfo.isReplicaLayer) 237 notesEl.textContent += '(replica)'; 238 239 if (layer.gpuMemoryUsageInBytes !== undefined) { 240 var rounded = bytesToRoundedMegabytes(layer.gpuMemoryUsageInBytes); 241 if (rounded !== 0) 242 notesEl.textContent += ' (' + rounded + ' MB)'; 243 } 244 245 item.layer = layer; 246 this.itemList_.appendChild(item); 247 248 if (layer.layerId == selectedLayerId) { 249 layer.selectionState = tr.model.SelectionState.SELECTED; 250 item.selected = true; 251 } 252 }, this); 253 } finally { 254 this.changingItemSelection_ = false; 255 } 256 }, 257 258 createElementWithDepth_: function(depth) { 259 var item = document.createElement('div'); 260 261 var indentEl = item.appendChild(tr.ui.b.createSpan()); 262 indentEl.style.whiteSpace = 'pre'; 263 for (var i = 0; i < depth; i++) 264 indentEl.textContent = indentEl.textContent + ' '; 265 return item; 266 }, 267 268 onItemSelectionChanged_: function(e) { 269 if (this.changingItemSelection_) 270 return; 271 if (this.renderPassQuads_) 272 this.onRenderPassSelected_(e); 273 else 274 this.onLayerSelected_(e); 275 tr.b.dispatchSimpleEvent(this, 'selection-change', false); 276 }, 277 278 onRenderPassSelected_: function(e) { 279 var selectedRenderPass; 280 var selectedRenderPassId; 281 if (this.itemList_.selectedElement) { 282 selectedRenderPass = this.itemList_.selectedElement.renderPass; 283 selectedRenderPassId = 284 this.itemList_.selectedElement.renderPassId; 285 } 286 287 if (selectedRenderPass) { 288 this.selection_ = new tr.ui.e.chrome.cc.RenderPassSelection( 289 selectedRenderPass, selectedRenderPassId); 290 } else { 291 this.selection_ = undefined; 292 } 293 }, 294 295 onLayerSelected_: function(e) { 296 var selectedLayer; 297 if (this.itemList_.selectedElement) 298 selectedLayer = this.itemList_.selectedElement.layer; 299 300 if (selectedLayer) 301 this.selection_ = new tr.ui.e.chrome.cc.LayerSelection(selectedLayer); 302 else 303 this.selection_ = undefined; 304 }, 305 306 get selection() { 307 return this.selection_; 308 }, 309 310 set selection(selection) { 311 if (this.selection_ == selection) 312 return; 313 this.selection_ = selection; 314 this.updateContents_(); 315 } 316 }; 317 318 return { 319 LayerPicker: LayerPicker 320 }; 321}); 322</script> 323