1/* 2 * Copyright 2017, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {transform, nanos_to_string, get_visible_chip} from './transform.js' 18import { fill_occlusion_state, fill_inherited_state } from './sf_visibility.js'; 19 20var RELATIVE_Z_CHIP = {short: 'RelZ', 21 long: "Is relative Z-ordered to another surface", 22 class: 'warn'}; 23var RELATIVE_Z_PARENT_CHIP = {short: 'RelZParent', 24 long: "Something is relative Z-ordered to this surface", 25 class: 'warn'}; 26var MISSING_LAYER = {short: 'MissingLayer', 27 long: "This layer was referenced from the parent, but not present in the trace", 28 class: 'error'}; 29var GPU_CHIP = {short: 'GPU', 30 long: "This layer was composed on the GPU", 31 class: 'gpu'}; 32var HWC_CHIP = {short: 'HWC', 33 long: "This layer was composed by Hardware Composer", 34 class: 'hwc'}; 35 36function transform_layer(layer) { 37 function offset_to(bounds, x, y) { 38 return { 39 right: bounds.right - (bounds.left - x), 40 bottom: bounds.bottom - (bounds.top - y), 41 left: x, 42 top: y, 43 }; 44 } 45 46 function get_rect(layer) { 47 var result = layer.bounds; 48 var tx = layer.position ? layer.position.x || 0 : 0; 49 var ty = layer.position ? layer.position.y || 0 : 0; 50 result = offset_to(result, 0, 0); 51 result.label = layer.name; 52 result.transform = layer.transform; 53 result.transform.tx = tx; 54 result.transform.ty = ty; 55 return result; 56 } 57 58 function add_hwc_composition_type_chip(layer) { 59 if (layer.hwcCompositionType === "CLIENT") { 60 chips.push(GPU_CHIP); 61 } else if (layer.hwcCompositionType === "DEVICE" || layer.hwcCompositionType === "SOLID_COLOR") { 62 chips.push(HWC_CHIP); 63 } 64 } 65 66 var chips = []; 67 if (layer.visible) { 68 chips.push(get_visible_chip()); 69 } 70 if ((layer.zOrderRelativeOf || -1) !== -1) { 71 chips.push(RELATIVE_Z_CHIP); 72 } 73 if (layer.zOrderRelativeParentOf !== undefined) { 74 chips.push(RELATIVE_Z_PARENT_CHIP); 75 } 76 if (layer.missing) { 77 chips.push(MISSING_LAYER); 78 } 79 add_hwc_composition_type_chip(layer); 80 const rect = layer.visible ? get_rect(layer) : undefined; 81 82 return transform({ 83 obj: layer, 84 kind: '', 85 name: layer.id + ": " + layer.name, 86 children: [[layer.resolvedChildren, transform_layer]], 87 rect, 88 undefined /* bounds */, 89 highlight: rect, 90 chips, 91 visible: layer.visible, 92 }); 93} 94 95function missingLayer(childId) { 96 return { 97 name: "layer #" + childId, 98 missing: true, 99 zOrderRelativeOf: -1, 100 transform: {dsdx:1, dtdx:0, dsdy:0, dtdy:1}, 101 } 102} 103 104function transform_layers(includesCompositionState, layers) { 105 var idToItem = {}; 106 var isChild = {} 107 108 var layersList = layers.layers || []; 109 110 layersList.forEach((e) => { 111 idToItem[e.id] = e; 112 }); 113 layersList.forEach((e) => { 114 e.resolvedChildren = []; 115 if (Array.isArray(e.children)) { 116 e.resolvedChildren = e.children.map( 117 (childId) => idToItem[childId] || missingLayer(childId)); 118 e.children.forEach((childId) => { 119 isChild[childId] = true; 120 }); 121 } 122 if ((e.zOrderRelativeOf || -1) !== -1) { 123 idToItem[e.zOrderRelativeOf].zOrderRelativeParentOf = e.id; 124 } 125 }); 126 127 var roots = layersList.filter((e) => !isChild[e.id]); 128 fill_inherited_state(idToItem, roots); 129 fill_occlusion_state(idToItem, roots, includesCompositionState); 130 function foreachTree(nodes, fun) { 131 nodes.forEach((n) => { 132 fun(n); 133 foreachTree(n.children, fun); 134 }); 135 } 136 137 var idToTransformed = {}; 138 var transformed_roots = roots.map((r) => 139 transform_layer(r, {parentBounds: {left: 0, right: 0, top: 0, bottom: 0}, 140 parentHidden: null})); 141 142 foreachTree(transformed_roots, (n) => { 143 idToTransformed[n.obj.id] = n; 144 }); 145 var flattened = []; 146 layersList.forEach((e) => { 147 flattened.push(idToTransformed[e.id]); 148 }); 149 150 return transform({ 151 obj: {}, 152 kind: 'layers', 153 name: 'layers', 154 children: [ 155 [transformed_roots, (c) => c], 156 ], 157 rects_transform (r) { 158 var res = []; 159 flattened.forEach((l) => { 160 if (l.rect) { 161 res.push(l.rect); 162 } 163 }); 164 return res.reverse(); 165 }, 166 flattened, 167 }); 168} 169 170function transform_layers_entry(entry) { 171 const includesCompositionState = !entry.excludesCompositionState; 172 return transform({ 173 obj: entry, 174 kind: 'entry', 175 name: nanos_to_string(entry.elapsedRealtimeNanos) + " - " + entry.where, 176 children: [ 177 [[entry.layers], (layer) => transform_layers(includesCompositionState, layer)], 178 ], 179 timestamp: entry.elapsedRealtimeNanos, 180 stableId: 'entry', 181 }); 182} 183 184function transform_layers_trace(entries) { 185 var r = transform({ 186 obj: entries, 187 kind: 'layerstrace', 188 name: 'layerstrace', 189 children: [ 190 [entries.entry, transform_layers_entry], 191 ], 192 }); 193 194 return r; 195} 196 197export {transform_layers, transform_layers_trace}; 198