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 #ifndef USE_ROSEN_DRAWING
22 #include "include/core/SkCanvas.h"
23 #include "include/core/SkColor.h"
24 #endif
25
26 #include "frame_collector.h"
27
28 namespace OHOS {
29 namespace Rosen {
30 namespace {
31 constexpr ::OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001400, "FramePainter" };
32 } // namespace
33
FramePainter(FrameCollector & collector)34 FramePainter::FramePainter(FrameCollector &collector) : collector_(collector)
35 {
36 }
37
38 #ifndef USE_ROSEN_DRAWING
Draw(SkCanvas & canvas)39 void FramePainter::Draw(SkCanvas &canvas)
40 #else
41 void FramePainter::Draw(Drawing::Canvas &canvas)
42 #endif
43 {
44 if (collector_.IsEnabled() == false) {
45 return;
46 }
47
48 #ifndef USE_ROSEN_DRAWING
49 auto width = canvas.imageInfo().width();
50 auto height = canvas.imageInfo().height();
51 #else
52 auto width = canvas.GetWidth();
53 auto height = canvas.GetHeight();
54 #endif
55 ::OHOS::HiviewDFX::HiLog::Debug(LABEL, "FramePainter::Draw %{public}dx%{public}d", width, height);
56
57 constexpr auto normalFPS = 60;
58 constexpr auto slowFPS = normalFPS / 2;
59 auto bars = GenerateTimeBars(width, height, normalFPS);
60 #ifndef USE_ROSEN_DRAWING
61 SkPaint paint;
62 paint.setStyle(paint.kFill_Style);
63 #else
64 Drawing::Brush brush;
65 #endif
66 for (const auto &[isHeavy, color, x, y, w, h] : bars) {
67 constexpr uint32_t heavyFrameAlpha = 0x7f;
68 constexpr uint32_t lightFrameAlpha = 0x3f;
69 auto alpha = isHeavy ? heavyFrameAlpha : lightFrameAlpha;
70 constexpr uint32_t alphaOffset = 24; // ARGB
71 #ifndef USE_ROSEN_DRAWING
72 paint.setColor(color | (alpha << alphaOffset));
73 canvas.drawRect(SkRect::MakeXYWH(x, y, w, h), paint);
74 #else
75 brush.SetColor(color | (alpha << alphaOffset));
76 canvas.AttachBrush(brush);
77 canvas.DrawRect(Drawing::Rect(x, y, w + x, h + y));
78 canvas.DetachBrush();
79 #endif
80 }
81
82 // normal fps line: alpha: 0xbf, green #00ff00
83 DrawFPSLine(canvas, normalFPS, height / frameTotalMs, 0xbf00ff00);
84
85 // slow fps line: alpha: 0xbf, red #ff0000
86 DrawFPSLine(canvas, slowFPS, height / frameTotalMs, 0xbfff0000);
87 }
88
89 #ifndef USE_ROSEN_DRAWING
DrawFPSLine(SkCanvas & canvas,uint32_t fps,double thickness,uint32_t color)90 void FramePainter::DrawFPSLine(SkCanvas &canvas, uint32_t fps, double thickness, uint32_t color)
91 #else
92 void FramePainter::DrawFPSLine(Drawing::Canvas &canvas, uint32_t fps, double thickness, uint32_t color)
93 #endif
94 {
95 if (fps == 0) {
96 return;
97 }
98
99 #ifndef USE_ROSEN_DRAWING
100 auto width = canvas.imageInfo().width();
101 auto height = canvas.imageInfo().height();
102 #else
103 auto width = canvas.GetWidth();
104 auto height = canvas.GetHeight();
105 #endif
106 auto heightPerMs = height / frameTotalMs;
107
108 constexpr auto OneSecondInMs = 1000.0;
109 auto bottom = OneSecondInMs / fps * heightPerMs;
110 auto lineOffset = thickness / 0x2; // vertical align center
111 #ifndef USE_ROSEN_DRAWING
112 auto fpsLine = SkRect::MakeXYWH(0, height - (bottom - lineOffset), width, thickness);
113
114 SkPaint paint;
115 paint.setStyle(paint.kFill_Style);
116 paint.setColor(color);
117 canvas.drawRect(fpsLine, paint);
118 #else
119 auto fpsLine = Drawing::Rect(0, height - (bottom - lineOffset), width, thickness + height - (bottom - lineOffset));
120
121 Drawing::Brush brush;
122 brush.SetColor(color);
123 canvas.AttachBrush(brush);
124 canvas.DrawRect(fpsLine);
125 canvas.DetachBrush();
126 #endif
127 }
128
GenerateTimeBars(uint32_t width,uint32_t height,uint32_t fps)129 std::vector<struct FramePainter::TimeBar> FramePainter::GenerateTimeBars(
130 uint32_t width, uint32_t height, uint32_t fps)
131 {
132 std::vector<struct TimeBar> bars;
133
134 auto heightPerMs = height / frameTotalMs;
135 constexpr auto reservedSize = 2.0;
136 auto barWidth = width / (frameQueueMaxSize + reservedSize);
137 auto offsetX = barWidth * frameQueueMaxSize - barWidth;
138
139 auto frameQueue = collector_.LockGetFrameQueue();
140 for (auto rit = frameQueue.rbegin(); rit != frameQueue.rend(); rit++) {
141 constexpr auto OneSecondInMs = 1000.0;
142 bool isHeavy = false;
143 if (fps != 0) {
144 isHeavy = SumTimesInMs(*rit) >= (OneSecondInMs / fps);
145 }
146 auto offsetY = height;
147 constexpr auto loopstart = static_cast<size_t>(FrameEventType::LoopStart);
148 constexpr auto loopend = static_cast<size_t>(FrameEventType::LoopEnd);
149 constexpr size_t frameEventTypeInterval = 2;
150 for (size_t i = loopstart; i < loopend; i += frameEventTypeInterval) {
151 auto it = frameEventColorMap.find(static_cast<FrameEventType>(i));
152 if (it == frameEventColorMap.end()) {
153 continue;
154 }
155 auto color = it->second;
156
157 constexpr double nanosecondsToMilliseconds = 1e6;
158 double diffMs = (rit->times[i + 1] - rit->times[i]) / nanosecondsToMilliseconds;
159 if (diffMs < 0) {
160 ::OHOS::HiviewDFX::HiLog::Warn(LABEL, "FramePainter::Draw %{public}zu range is negative", i);
161 continue;
162 } else if (diffMs == 0) {
163 continue;
164 }
165
166 auto diffHeight = diffMs * heightPerMs;
167 offsetY -= diffHeight;
168 struct TimeBar bar = {
169 .isHeavy = isHeavy,
170 .color = color,
171 .posX = offsetX,
172 .posY = offsetY,
173 .width = barWidth,
174 .height = diffHeight,
175 };
176 bars.push_back(bar);
177 }
178 offsetX -= barWidth;
179 }
180 collector_.UnlockFrameQueue();
181
182 return bars;
183 }
184
SumTimesInMs(const struct FrameInfo & info)185 double FramePainter::SumTimesInMs(const struct FrameInfo &info)
186 {
187 auto sumMs = 0.0;
188 constexpr auto loopstart = static_cast<size_t>(FrameEventType::LoopStart);
189 constexpr auto loopend = static_cast<size_t>(FrameEventType::LoopEnd);
190 constexpr size_t frameEventTypeInterval = 2;
191 for (size_t i = loopstart; i < loopend; i += frameEventTypeInterval) {
192 const auto &cm = frameEventColorMap;
193 if (cm.find(static_cast<FrameEventType>(i)) == cm.end()) {
194 continue;
195 }
196
197 constexpr double nanosecondsToMilliseconds = 1e6;
198 double diffMs = (info.times[i + 1] - info.times[i]) / nanosecondsToMilliseconds;
199 if (diffMs <= 0) {
200 continue;
201 }
202
203 sumMs += diffMs;
204 }
205
206 return sumMs;
207 }
208 } // namespace Rosen
209 } // namespace OHOS
210