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