1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "frame_painter.h"
17
18 #include <map>
19
20 #include "hilog/log.h"
21
22 #include "frame_collector.h"
23
24 namespace OHOS {
25 namespace Rosen {
26 #undef LOG_DOMAIN
27 #define LOG_DOMAIN 0xD001400
28
29 #undef LOG_TAG
30 #define LOG_TAG "FramePainter"
31 #define LOGW(fmt, ...) HILOG_WARN(LOG_CORE, fmt, ##__VA_ARGS__)
32 #define LOGD(fmt, ...) HILOG_DEBUG(LOG_CORE, fmt, ##__VA_ARGS__)
33
FramePainter(FrameCollector & collector)34 FramePainter::FramePainter(FrameCollector &collector) : collector_(collector)
35 {
36 }
37
Draw(Drawing::Canvas & canvas)38 void FramePainter::Draw(Drawing::Canvas &canvas)
39 {
40 if (collector_.IsEnabled() == false) {
41 return;
42 }
43
44 auto width = canvas.GetWidth();
45 auto height = canvas.GetHeight();
46 LOGD("FramePainter::Draw %{public}dx%{public}d", width, height);
47
48 constexpr auto normalFPS = 60;
49 constexpr auto slowFPS = normalFPS / 2;
50 auto bars = GenerateTimeBars(width, height, normalFPS);
51 Drawing::Brush brush;
52 for (const auto &[isHeavy, color, x, y, w, h] : bars) {
53 constexpr uint32_t heavyFrameAlpha = 0x7f;
54 constexpr uint32_t lightFrameAlpha = 0x3f;
55 auto alpha = isHeavy ? heavyFrameAlpha : lightFrameAlpha;
56 constexpr uint32_t alphaOffset = 24; // ARGB
57 brush.SetColor(color | (alpha << alphaOffset));
58 canvas.AttachBrush(brush);
59 canvas.DrawRect(Drawing::Rect(x, y, w + x, h + y));
60 canvas.DetachBrush();
61 }
62
63 // normal fps line: alpha: 0xbf, green #00ff00
64 DrawFPSLine(canvas, normalFPS, height / frameTotalMs, 0xbf00ff00);
65
66 // slow fps line: alpha: 0xbf, red #ff0000
67 DrawFPSLine(canvas, slowFPS, height / frameTotalMs, 0xbfff0000);
68 }
69
DrawFPSLine(Drawing::Canvas & canvas,uint32_t fps,double thickness,uint32_t color)70 void FramePainter::DrawFPSLine(Drawing::Canvas &canvas, uint32_t fps, double thickness, uint32_t color)
71 {
72 if (fps == 0) {
73 return;
74 }
75
76 auto width = canvas.GetWidth();
77 auto height = canvas.GetHeight();
78 auto heightPerMs = height / frameTotalMs;
79
80 constexpr auto OneSecondInMs = 1000.0;
81 auto bottom = OneSecondInMs / fps * heightPerMs;
82 auto lineOffset = thickness / 0x2; // vertical align center
83 auto fpsLine = Drawing::Rect(0, height - (bottom - lineOffset), width, thickness + height - (bottom - lineOffset));
84
85 Drawing::Brush brush;
86 brush.SetColor(color);
87 canvas.AttachBrush(brush);
88 canvas.DrawRect(fpsLine);
89 canvas.DetachBrush();
90 }
91
GenerateTimeBars(uint32_t width,uint32_t height,uint32_t fps)92 std::vector<struct FramePainter::TimeBar> FramePainter::GenerateTimeBars(
93 uint32_t width, uint32_t height, uint32_t fps)
94 {
95 std::vector<struct TimeBar> bars;
96
97 auto heightPerMs = height / frameTotalMs;
98 constexpr auto reservedSize = 2.0;
99 auto barWidth = width / (frameQueueMaxSize + reservedSize);
100 auto offsetX = barWidth * frameQueueMaxSize - barWidth;
101
102 auto frameQueue = collector_.LockGetFrameQueue();
103 for (auto rit = frameQueue.rbegin(); rit != frameQueue.rend(); rit++) {
104 constexpr auto OneSecondInMs = 1000.0;
105 bool isHeavy = false;
106 if (fps != 0) {
107 isHeavy = SumTimesInMs(*rit) >= (OneSecondInMs / fps);
108 }
109 auto offsetY = height;
110 constexpr auto loopstart = static_cast<size_t>(FrameEventType::LoopStart);
111 constexpr auto loopend = static_cast<size_t>(FrameEventType::LoopEnd);
112 constexpr size_t frameEventTypeInterval = 2;
113 for (size_t i = loopstart; i < loopend; i += frameEventTypeInterval) {
114 auto it = frameEventColorMap.find(static_cast<FrameEventType>(i));
115 if (it == frameEventColorMap.end()) {
116 continue;
117 }
118 auto color = it->second;
119
120 constexpr double nanosecondsToMilliseconds = 1e6;
121 double diffMs = (rit->times[i + 1] - rit->times[i]) / nanosecondsToMilliseconds;
122 if (diffMs < 0) {
123 LOGW("FramePainter::Draw %{public}zu range is negative", i);
124 continue;
125 } else if (diffMs == 0) {
126 continue;
127 }
128
129 auto diffHeight = diffMs * heightPerMs;
130 offsetY -= diffHeight;
131 struct TimeBar bar = {
132 .isHeavy = isHeavy,
133 .color = color,
134 .posX = offsetX,
135 .posY = offsetY,
136 .width = barWidth,
137 .height = diffHeight,
138 };
139 bars.push_back(bar);
140 }
141 offsetX -= barWidth;
142 }
143 collector_.UnlockFrameQueue();
144
145 return bars;
146 }
147
SumTimesInMs(const struct FrameInfo & info)148 double FramePainter::SumTimesInMs(const struct FrameInfo &info)
149 {
150 auto sumMs = 0.0;
151 constexpr auto loopstart = static_cast<size_t>(FrameEventType::LoopStart);
152 constexpr auto loopend = static_cast<size_t>(FrameEventType::LoopEnd);
153 constexpr size_t frameEventTypeInterval = 2;
154 for (size_t i = loopstart; i < loopend; i += frameEventTypeInterval) {
155 const auto &cm = frameEventColorMap;
156 if (cm.find(static_cast<FrameEventType>(i)) == cm.end()) {
157 continue;
158 }
159
160 constexpr double nanosecondsToMilliseconds = 1e6;
161 double diffMs = (info.times[i + 1] - info.times[i]) / nanosecondsToMilliseconds;
162 if (diffMs <= 0) {
163 continue;
164 }
165
166 sumMs += diffMs;
167 }
168
169 return sumMs;
170 }
171 } // namespace Rosen
172 } // namespace OHOS
173