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