blob: dc99b41cc6ddd1906272e488216cba7a744c6870 [file] [log] [blame]
Yiwei Zhang068e31b2018-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 std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
60 const LayerProtoParser::LayerGlobal* layerGlobal) {
61 for (std::unique_ptr<LayerProtoParser::Layer>& layer : layerTree) {
62 if (!layer) continue;
63 traverseLayerTreeStatsLocked(std::move(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.get()).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(std::move(layerTree), &layerGlobal);
87}
88
89void LayerStats::dump(String8& result) {
90 ATRACE_CALL();
91 ALOGD("Dumping");
92 result.append("Count,DstPosX,DstPosY,DstWidth,DstHeight,LayerType,WScale,HScale,");
93 result.append("Transform,PixelFormat,Dataspace\n");
94 std::lock_guard<std::mutex> lock(mMutex);
95 for (auto& u : mLayerStatsMap) {
96 result.appendFormat("%u,%s\n", u.second, u.first.c_str());
97 }
98}
99
100const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
101 static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
102 int32_t ratio = location * 8 / range;
103 if (ratio < 0) return "N/A";
104 if (isHorizontal) {
105 // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
106 if (ratio > 6) return "3/4";
107 // use index 0, 2, 4, 6
108 return locationArray[ratio & ~1];
109 }
110 if (ratio > 7) return "7/8";
111 return locationArray[ratio];
112}
113
114const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
115 static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
116 int32_t ratio = size * 8 / range;
117 if (ratio < 0) return "N/A";
118 if (isWidth) {
119 // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
120 if (ratio > 6) return "1";
121 // use index 1, 3, 5, 7
122 return sizeArray[ratio | 1];
123 }
124 if (ratio > 7) return "1";
125 return sizeArray[ratio];
126}
127
128const char* LayerStats::layerTransform(int32_t transform) {
129 return getTransformName(static_cast<hwc_transform_t>(transform));
130}
131
132std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
133 if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
134 std::string ret = "";
135 if (isRotated(layer->hwcTransform)) {
136 ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
137 static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
138 ret += ",";
139 ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
140 static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
141 } else {
142 ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
143 static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
144 ret += ",";
145 ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
146 static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
147 }
148 return ret;
149}
150
151const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
152 // Make scale buckets from <1/64 to >= 16, to avoid floating point
153 // calculation, x64 on destinationScale first
154 int32_t scale = destinationScale * 64 / sourceScale;
155 if (!scale) return "<1/64";
156 if (scale < 2) return "1/64";
157 if (scale < 4) return "1/32";
158 if (scale < 8) return "1/16";
159 if (scale < 16) return "1/8";
160 if (scale < 32) return "1/4";
161 if (scale < 64) return "1/2";
162 if (scale < 128) return "1";
163 if (scale < 256) return "2";
164 if (scale < 512) return "4";
165 if (scale < 1024) return "8";
166 return ">=16";
167}
168
169bool LayerStats::isRotated(int32_t transform) {
170 return transform & HWC_TRANSFORM_ROT_90;
171}
172
173bool LayerStats::isVFlipped(int32_t transform) {
174 return transform & HWC_TRANSFORM_FLIP_V;
175}
176
177bool LayerStats::isHFlipped(int32_t transform) {
178 return transform & HWC_TRANSFORM_FLIP_H;
179}
180
181} // namespace android