1 /* <lambda>null2 * Copyright (C) 2023 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 17 package android.tools.traces.parsers.perfetto 18 19 import android.graphics.Color 20 import android.graphics.Rect 21 import android.graphics.RectF 22 import android.graphics.Region 23 import android.tools.Timestamp 24 import android.tools.datatypes.ActiveBuffer 25 import android.tools.datatypes.Matrix33 26 import android.tools.datatypes.Size 27 import android.tools.datatypes.emptyColor 28 import android.tools.parsers.AbstractTraceParser 29 import android.tools.traces.surfaceflinger.Display 30 import android.tools.traces.surfaceflinger.HwcCompositionType 31 import android.tools.traces.surfaceflinger.Layer 32 import android.tools.traces.surfaceflinger.LayerTraceEntry 33 import android.tools.traces.surfaceflinger.LayerTraceEntryBuilder 34 import android.tools.traces.surfaceflinger.LayersTrace 35 import android.tools.traces.surfaceflinger.Transform 36 import android.tools.traces.surfaceflinger.Transform.Companion.isFlagClear 37 import android.tools.traces.surfaceflinger.Transform.Companion.isFlagSet 38 import android.tools.withCache 39 import android.tools.withTracing 40 41 /** Parser for [LayersTrace] */ 42 class LayersTraceParser( 43 private val ignoreLayersStackMatchNoDisplay: Boolean = true, 44 private val ignoreLayersInVirtualDisplay: Boolean = true, 45 private val orphanLayerCallback: ((Layer) -> Boolean)? = null, 46 ) : AbstractTraceParser<TraceProcessorSession, LayerTraceEntry, LayerTraceEntry, LayersTrace>() { 47 48 override val traceName = "Layers trace (SF)" 49 50 override fun createTrace(entries: Collection<LayerTraceEntry>): LayersTrace { 51 return LayersTrace(entries) 52 } 53 54 override fun doDecodeByteArray(bytes: ByteArray): TraceProcessorSession { 55 error("This parser can only read from perfetto trace processor") 56 } 57 58 override fun shouldParseEntry(entry: LayerTraceEntry) = true 59 60 override fun getEntries(input: TraceProcessorSession): List<LayerTraceEntry> { 61 val realToMonotonicTimeOffsetNs = 62 queryRealToMonotonicTimeOffsetNs(input, "surfaceflinger_layers_snapshot") 63 64 return input.query(getSqlQuerySnapshots()) { snapshotsRows -> 65 val traceEntries = mutableListOf<LayerTraceEntry>() 66 val snapshotGroups = snapshotsRows.groupBy { it["snapshot_id"] } 67 68 for (snapshotId in 0L until snapshotGroups.size) { 69 withTracing("query + build entry") { 70 val layerRows = 71 withTracing("query layer rows") { 72 input.query(getSqlQueryLayers(snapshotId)) { it } 73 } 74 withTracing("build entry") { 75 val snapshotRows = snapshotGroups[snapshotId]!! 76 val entry = 77 buildTraceEntry(snapshotRows, layerRows, realToMonotonicTimeOffsetNs) 78 traceEntries.add(entry) 79 } 80 } 81 } 82 83 traceEntries 84 } 85 } 86 87 override fun getTimestamp(entry: LayerTraceEntry): Timestamp = entry.timestamp 88 89 override fun onBeforeParse(input: TraceProcessorSession) {} 90 91 override fun doParseEntry(entry: LayerTraceEntry) = entry 92 93 private fun buildTraceEntry( 94 snapshotRows: List<Row>, 95 layersRows: List<Row>, 96 realToMonotonicTimeOffsetNs: Long 97 ): LayerTraceEntry { 98 val snapshotArgs = Args.build(snapshotRows) 99 val displays = snapshotArgs.getChildren("displays")?.map { newDisplay(it) } ?: emptyList() 100 val excludesCompositionState = 101 snapshotArgs.getChild("excludes_composition_state")?.getBoolean() ?: false 102 103 val idAndLayers = 104 layersRows 105 .groupBy { it["layer_id"].toString() } 106 .map { (layerId, layerRows) -> 107 Pair(layerId, newLayer(Args.build(layerRows), excludesCompositionState)) 108 } 109 .toMutableList() 110 idAndLayers.sortBy { it.first.toLong() } 111 112 val layers = idAndLayers.map { it.second } 113 114 return LayerTraceEntryBuilder() 115 .setElapsedTimestamp(snapshotArgs.getChild("elapsed_realtime_nanos")?.getLong() ?: 0L) 116 .setRealToElapsedTimeOffsetNs(realToMonotonicTimeOffsetNs) 117 .setLayers(layers) 118 .setDisplays(displays) 119 .setVSyncId(snapshotArgs.getChild("vsync_id")?.getLong() ?: 0L) 120 .setHwcBlob(snapshotArgs.getChild("hwc_blob")?.getString() ?: "") 121 .setWhere(snapshotArgs.getChild("where")?.getString() ?: "") 122 .setOrphanLayerCallback(orphanLayerCallback) 123 .ignoreLayersStackMatchNoDisplay(ignoreLayersStackMatchNoDisplay) 124 .ignoreVirtualDisplay(ignoreLayersInVirtualDisplay) 125 .build() 126 } 127 128 companion object { 129 private fun getSqlQuerySnapshots(): String { 130 return """ 131 SELECT 132 sfs.id AS snapshot_id, 133 sfs.ts as ts, 134 args.key as key, 135 args.display_value as value, 136 args.value_type as value_type 137 FROM surfaceflinger_layers_snapshot AS sfs 138 INNER JOIN args ON sfs.arg_set_id = args.arg_set_id; 139 """ 140 .trimIndent() 141 } 142 143 private fun getSqlQueryLayers(snapshotId: Long): String { 144 return """ 145 SELECT 146 sfl.snapshot_id, 147 sfl.id as layer_id, 148 args.key as key, 149 args.display_value as value, 150 args.value_type 151 FROM 152 surfaceflinger_layer as sfl 153 INNER JOIN args ON sfl.arg_set_id = args.arg_set_id 154 WHERE snapshot_id = $snapshotId; 155 """ 156 .trimIndent() 157 } 158 159 private fun newLayer(layer: Args, excludesCompositionState: Boolean): Layer { 160 // Differentiate between the cases when there's no HWC data on 161 // the trace, and when the visible region is actually empty 162 val activeBuffer = newActiveBuffer(layer.getChild("active_buffer")) 163 val visibleRegion = newRegion(layer.getChild("visible_region")) ?: Region() 164 val crop = newCropRect(layer.getChild("crop")) 165 return Layer.from( 166 layer.getChild("name")?.getString() ?: "", 167 layer.getChild("id")?.getInt() ?: 0, 168 layer.getChild("parent")?.getInt() ?: 0, 169 layer.getChild("z")?.getInt() ?: 0, 170 visibleRegion, 171 activeBuffer, 172 layer.getChild("flags")?.getInt() ?: 0, 173 newRectF(layer.getChild("bounds")), 174 newColor(layer.getChild("color")), 175 layer.getChild("is_opaque")?.getBoolean() ?: false, 176 layer.getChild("shadow_radius")?.getFloat() ?: 0f, 177 layer.getChild("corner_radius")?.getFloat() ?: 0f, 178 newRectF(layer.getChild("screen_bounds")), 179 newTransform(layer.getChild("transform"), position = layer.getChild("position")), 180 layer.getChild("curr_frame")?.getLong() ?: -1, 181 layer.getChild("effective_scaling_mode")?.getInt() ?: 0, 182 newTransform(layer.getChild("buffer_transform"), position = null), 183 newHwcCompositionType(layer.getChild("hwc_composition_type")), 184 layer.getChild("background_blur_radius")?.getInt() ?: 0, 185 crop, 186 layer.getChild("is_relative_of")?.getBoolean() ?: false, 187 layer.getChild("z_order_relative_of")?.getInt() ?: 0, 188 layer.getChild("layer_stack")?.getInt() ?: 0, 189 excludesCompositionState 190 ) 191 } 192 193 private fun newDisplay(display: Args): Display { 194 return Display.from( 195 display.getChild("id")?.getLong() ?: 0L, 196 display.getChild("name")?.getString() ?: "", 197 display.getChild("layer_stack")?.getInt() ?: 0, 198 newSize(display.getChild("size")), 199 newRect(display.getChild("layer_stack_space_rect")), 200 newTransform(display.getChild("transform"), position = null), 201 display.getChild("is_virtual")?.getBoolean() ?: false, 202 display.getChild("dpi_x")?.getFloat()?.toDouble() ?: 0.0, 203 display.getChild("dpi_y")?.getFloat()?.toDouble() ?: 0.0, 204 ) 205 } 206 207 private fun newRectF(rectf: Args?): RectF { 208 if (rectf == null) { 209 return RectF() 210 } 211 return RectF( 212 /* left */ rectf.getChild("left")?.getFloat() ?: 0f, 213 /* top */ rectf.getChild("top")?.getFloat() ?: 0f, 214 /* right */ rectf.getChild("right")?.getFloat() ?: 0f, 215 /* bottom */ rectf.getChild("bottom")?.getFloat() ?: 0f 216 ) 217 } 218 219 private fun newSize(sizeArgs: Args?): Size { 220 if (sizeArgs == null) { 221 return Size.EMPTY 222 } 223 return Size.from( 224 sizeArgs.getChild("w")?.getInt() ?: 0, 225 sizeArgs.getChild("h")?.getInt() ?: 0 226 ) 227 } 228 229 private fun newColor(color: Args?): Color { 230 if (color == null) { 231 return emptyColor() 232 } 233 return withCache { 234 Color.valueOf( 235 color.getChild("r")?.getFloat() ?: 0f, 236 color.getChild("g")?.getFloat() ?: 0f, 237 color.getChild("b")?.getFloat() ?: 0f, 238 color.getChild("a")?.getFloat() ?: 0f 239 ) 240 } 241 } 242 243 private fun newActiveBuffer(buffer: Args?): ActiveBuffer { 244 if (buffer == null) { 245 return ActiveBuffer.EMPTY 246 } 247 return ActiveBuffer.from( 248 buffer.getChild("width")?.getInt() ?: 0, 249 buffer.getChild("height")?.getInt() ?: 0, 250 buffer.getChild("stride")?.getInt() ?: 0, 251 buffer.getChild("format")?.getInt() ?: 0 252 ) 253 } 254 255 private fun newHwcCompositionType(value: Args?): HwcCompositionType { 256 if (value == null || !value.isString()) { 257 return HwcCompositionType.HWC_TYPE_UNRECOGNIZED 258 } 259 return HwcCompositionType.valueOf(value.getString()) 260 } 261 262 private fun newCropRect(crop: Args?): RectF? { 263 if (crop == null) { 264 return RectF() 265 } 266 267 val right = crop.getChild("right")?.getInt() ?: 0 268 val left = crop.getChild("left")?.getInt() ?: 0 269 val bottom = crop.getChild("bottom")?.getInt() ?: 0 270 val top = crop.getChild("top")?.getInt() ?: 0 271 272 // crop (0,0) (-1,-1) means no crop 273 if (right == -1 && left == 0 && bottom == -1 && top == 0) { 274 return null 275 } 276 277 return RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) 278 } 279 280 private fun newRegion(region: Args?): Region? { 281 if (region == null) { 282 return null 283 } 284 val result = Region() 285 val rects = region.getChildren("rect")?.map { newRect(it) } ?: emptyList() 286 rects.forEach { rect -> result.op(rect, Region.Op.UNION) } 287 return result 288 } 289 290 private fun newRect(rect: Args?): Rect = 291 Rect( 292 rect?.getChild("left")?.getInt() ?: 0, 293 rect?.getChild("top")?.getInt() ?: 0, 294 rect?.getChild("right")?.getInt() ?: 0, 295 rect?.getChild("bottom")?.getInt() ?: 0 296 ) 297 298 private fun newTransform(transform: Args?, position: Args?) = 299 Transform.from(transform?.getChild("type")?.getInt(), getMatrix(transform, position)) 300 301 private fun getMatrix(transform: Args?, position: Args?): Matrix33 { 302 val x = position?.getChild("x")?.getFloat() ?: 0f 303 val y = position?.getChild("y")?.getFloat() ?: 0f 304 305 if ( 306 transform == null || 307 Transform.isSimpleTransform(transform.getChild("type")?.getInt()) 308 ) { 309 return transform?.getChild("type")?.getInt().getDefaultTransform(x, y) 310 } 311 312 return Matrix33.from( 313 transform.getChild("dsdx")?.getFloat() ?: 0f, 314 transform.getChild("dtdx")?.getFloat() ?: 0f, 315 x, 316 transform.getChild("dsdy")?.getFloat() ?: 0f, 317 transform.getChild("dtdy")?.getFloat() ?: 0f, 318 y 319 ) 320 } 321 322 private fun Int?.getDefaultTransform(x: Float, y: Float): Matrix33 { 323 return when { 324 // IDENTITY 325 this == null -> Matrix33.identity(x, y) 326 // // ROT_270 = ROT_90|FLIP_H|FLIP_V 327 isFlagSet(Transform.ROT_90_VAL or Transform.FLIP_V_VAL or Transform.FLIP_H_VAL) -> 328 Matrix33.rot270(x, y) 329 // ROT_180 = FLIP_H|FLIP_V 330 isFlagSet(Transform.FLIP_V_VAL or Transform.FLIP_H_VAL) -> Matrix33.rot180(x, y) 331 // ROT_90 332 isFlagSet(Transform.ROT_90_VAL) -> Matrix33.rot90(x, y) 333 // IDENTITY 334 isFlagClear(Transform.SCALE_VAL or Transform.ROTATE_VAL) -> Matrix33.identity(x, y) 335 else -> throw IllegalStateException("Unknown transform type $this") 336 } 337 } 338 } 339 } 340