blob: ea2542c17341f28b8d4e72267537f1f162e221fe [file] [log] [blame]
Yiwei Zhang7124ad32018-02-21 13:02:45 -08001/*
2 * Copyright 2018 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#undef LOG_TAG
17#define LOG_TAG "LayerStats"
18#define ATRACE_TAG ATRACE_TAG_GRAPHICS
19
20#include "LayerStats.h"
21#include "DisplayHardware/HWComposer.h"
22
23#include <android-base/stringprintf.h>
24#include <log/log.h>
25#include <utils/String8.h>
26#include <utils/Trace.h>
27
28namespace android {
29
30void LayerStats::enable() {
31 ATRACE_CALL();
32 std::lock_guard<std::mutex> lock(mMutex);
33 if (mEnabled) return;
34 mLayerStatsMap.clear();
35 mEnabled = true;
36 ALOGD("Logging enabled");
37}
38
39void LayerStats::disable() {
40 ATRACE_CALL();
41 std::lock_guard<std::mutex> lock(mMutex);
42 if (!mEnabled) return;
43 mEnabled = false;
44 ALOGD("Logging disabled");
45}
46
47void LayerStats::clear() {
48 ATRACE_CALL();
49 std::lock_guard<std::mutex> lock(mMutex);
50 mLayerStatsMap.clear();
51 ALOGD("Cleared current layer stats");
52}
53
54bool LayerStats::isEnabled() {
55 return mEnabled;
56}
57
58void LayerStats::traverseLayerTreeStatsLocked(
59 const std::vector<const LayerProtoParser::Layer*>& layerTree,
60 const LayerProtoParser::LayerGlobal* layerGlobal) {
61 for (auto layer : layerTree) {
62 if (!layer) continue;
63 traverseLayerTreeStatsLocked(layer->children, layerGlobal);
64 std::string key =
65 base::StringPrintf("%s,%s,%s,%s,%s,%s,%s,%s,%s",
66 destinationLocation(layer->hwcFrame.left,
67 layerGlobal->resolution[0], true),
68 destinationLocation(layer->hwcFrame.top,
69 layerGlobal->resolution[1], false),
70 destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
71 layerGlobal->resolution[0], true),
72 destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
73 layerGlobal->resolution[1], false),
74 layer->type.c_str(), scaleRatioWH(layer).c_str(),
75 layerTransform(layer->hwcTransform), layer->pixelFormat.c_str(),
76 layer->dataspace.c_str());
77 mLayerStatsMap[key]++;
78 }
79}
80
81void LayerStats::logLayerStats(const LayersProto& layersProto) {
82 ATRACE_CALL();
83 auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
84 auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
85 std::lock_guard<std::mutex> lock(mMutex);
86 traverseLayerTreeStatsLocked(layerTree, &layerGlobal);
87 LayerProtoParser::destroyLayerTree(layerTree);
88}
89
90void LayerStats::dump(String8& result) {
91 ATRACE_CALL();
92 ALOGD("Dumping");
93 result.append("Count,DstPosX,DstPosY,DstWidth,DstHeight,LayerType,WScale,HScale,");
94 result.append("Transform,PixelFormat,Dataspace\n");
95 std::lock_guard<std::mutex> lock(mMutex);
96 for (auto& u : mLayerStatsMap) {
97 result.appendFormat("%u,%s\n", u.second, u.first.c_str());
98 }
99}
100
101const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
102 static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
103 int32_t ratio = location * 8 / range;
104 if (ratio < 0) return "N/A";
105 if (isHorizontal) {
106 // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
107 if (ratio > 6) return "3/4";
108 // use index 0, 2, 4, 6
109 return locationArray[ratio & ~1];
110 }
111 if (ratio > 7) return "7/8";
112 return locationArray[ratio];
113}
114
115const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
116 static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
117 int32_t ratio = size * 8 / range;
118 if (ratio < 0) return "N/A";
119 if (isWidth) {
120 // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
121 if (ratio > 6) return "1";
122 // use index 1, 3, 5, 7
123 return sizeArray[ratio | 1];
124 }
125 if (ratio > 7) return "1";
126 return sizeArray[ratio];
127}
128
129const char* LayerStats::layerTransform(int32_t transform) {
130 return getTransformName(static_cast<hwc_transform_t>(transform));
131}
132
133std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
134 if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
135 std::string ret = "";
136 if (isRotated(layer->hwcTransform)) {
137 ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
138 static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
139 ret += ",";
140 ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
141 static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
142 } else {
143 ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
144 static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
145 ret += ",";
146 ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
147 static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
148 }
149 return ret;
150}
151
152const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
153 // Make scale buckets from <1/64 to >= 16, to avoid floating point
154 // calculation, x64 on destinationScale first
155 int32_t scale = destinationScale * 64 / sourceScale;
156 if (!scale) return "<1/64";
157 if (scale < 2) return "1/64";
158 if (scale < 4) return "1/32";
159 if (scale < 8) return "1/16";
160 if (scale < 16) return "1/8";
161 if (scale < 32) return "1/4";
162 if (scale < 64) return "1/2";
163 if (scale < 128) return "1";
164 if (scale < 256) return "2";
165 if (scale < 512) return "4";
166 if (scale < 1024) return "8";
167 return ">=16";
168}
169
170bool LayerStats::isRotated(int32_t transform) {
171 return transform & HWC_TRANSFORM_ROT_90;
172}
173
174bool LayerStats::isVFlipped(int32_t transform) {
175 return transform & HWC_TRANSFORM_FLIP_V;
176}
177
178bool LayerStats::isHFlipped(int32_t transform) {
179 return transform & HWC_TRANSFORM_FLIP_H;
180}
181
182} // namespace android