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_collector.h"
17 
18 #include <chrono>
19 #include <mutex>
20 #include <map>
21 #include <string>
22 
23 #include "hilog/log.h"
24 #include "hitrace_meter.h"
25 #include "parameter.h"
26 
27 #include "frame_saver.h"
28 
29 namespace OHOS {
30 namespace Rosen {
31 
32 #undef LOG_DOMAIN
33 #define LOG_DOMAIN 0xD001400
34 
35 #undef LOG_TAG
36 #define LOG_TAG "FrameCollector"
37 
38 #define LOGW(fmt, ...) HILOG_WARN(LOG_CORE, fmt, ##__VA_ARGS__)
39 #define LOGD(fmt, ...) HILOG_DEBUG(LOG_CORE, fmt, ##__VA_ARGS__)
40 namespace {
41 constexpr int32_t uimarksStart = static_cast<int32_t>(FrameEventType::UIMarksStart);
42 constexpr int32_t uimarksEnd = static_cast<int32_t>(FrameEventType::UIMarksEnd) - 1;
43 constexpr int32_t loopEnd = static_cast<int32_t>(FrameEventType::LoopEnd) - 1;
44 constexpr int32_t vsyncStart = static_cast<int32_t>(FrameEventType::WaitVsyncStart);
45 constexpr int32_t vsyncEnd = static_cast<int32_t>(FrameEventType::WaitVsyncEnd);
46 } // namespace
47 
GetInstance()48 FrameCollector &FrameCollector::GetInstance()
49 {
50     static FrameCollector instance;
51     return instance;
52 }
53 
SetRepaintCallback(std::function<void ()> repaint)54 void FrameCollector::SetRepaintCallback(std::function<void()> repaint)
55 {
56     repaint_ = repaint;
57 }
58 
LockGetFrameQueue()59 const FrameInfoQueue &FrameCollector::LockGetFrameQueue()
60 {
61     frameQueueMutex_.lock();
62     return frameQueue_;
63 }
64 
UnlockFrameQueue()65 void FrameCollector::UnlockFrameQueue()
66 {
67     frameQueueMutex_.unlock();
68 }
69 
IsEnabled() const70 bool FrameCollector::IsEnabled() const
71 {
72     return enabled_;
73 }
74 
SetEnabled(bool enable)75 void FrameCollector::SetEnabled(bool enable)
76 {
77     enabled_ = enable;
78 }
79 
MarkFrameEvent(const FrameEventType & type,int64_t timeNs)80 void FrameCollector::MarkFrameEvent(const FrameEventType &type, int64_t timeNs)
81 {
82     const auto &index = static_cast<int32_t>(type);
83     if (index >= static_cast<int32_t>(FrameEventType::Max)) {
84         LOGW("FrameCollector::MarkFrameEvent index(%{public}d) not exists", static_cast<int32_t>(index));
85         return;
86     }
87 
88     if (timeNs == 0) {
89         timeNs = std::chrono::duration_cast<std::chrono::nanoseconds>(
90             std::chrono::steady_clock::now().time_since_epoch()).count();
91     }
92 
93     if (usingSaver_) {
94         saver_->SaveFrameEvent(type, timeNs);
95     }
96 
97     if (!enabled_) {
98         return;
99     }
100 
101     LOGD("FrameCollector::MarkFrameEvent index(%{public}d) occur at %{public}s", index, std::to_string(timeNs).c_str());
102     ProcessFrameEvent(index, timeNs);
103 }
104 
ProcessFrameEvent(int32_t index,int64_t timeNs)105 void FrameCollector::ProcessFrameEvent(int32_t index, int64_t timeNs)
106 {
107     std::lock_guard lockPending(pendingMutex_);
108     // lockFrameQueue: lock for {pbefore_, pafter_}
109     std::lock_guard lockFrameQueue(frameQueueMutex_);
110     if (ProcessUIMarkLocked(index, timeNs)) {
111         return;
112     }
113 
114     if (index == vsyncStart) {
115         pbefore_ = &frameQueue_.Push(FrameInfo());
116         pbefore_->frameNumber = currentUIMarks_.frameNumber;
117         for (auto i = uimarksStart; i <= uimarksEnd; i++) {
118             pbefore_->times[i] = currentUIMarks_.times[i];
119         }
120         pbefore_->times[index] = timeNs;
121 
122         if (haveAfterVsync_) {
123             pbefore_->skiped = true;
124             pbefore_->times[vsyncEnd] = pbefore_->times[vsyncStart];
125         } else {
126             StartAsyncTrace(HITRACE_TAG_GRAPHIC_AGP, GetAsyncNameByFrameEventType(index), pbefore_->frameNumber);
127         }
128         return;
129     }
130 
131     if (!haveAfterVsync_) {
132         haveAfterVsync_ = true;
133         pafter_ = pbefore_;
134     }
135 
136     if (pafter_ != nullptr) {
137         pafter_->times[index] = timeNs;
138 
139         if (IsStartFrameEventType(index)) {
140             StartAsyncTrace(HITRACE_TAG_GRAPHIC_AGP, GetAsyncNameByFrameEventType(index), pafter_->frameNumber);
141         } else {
142             FinishAsyncTrace(HITRACE_TAG_GRAPHIC_AGP, GetAsyncNameByFrameEventType(index), pafter_->frameNumber);
143         }
144     }
145 
146     if (index == loopEnd) {
147         haveAfterVsync_ = false;
148     }
149 }
150 
ProcessUIMarkLocked(int32_t index,int64_t timeNs)151 bool FrameCollector::ProcessUIMarkLocked(int32_t index, int64_t timeNs)
152 {
153     if (index > uimarksEnd) {
154         return false;
155     }
156 
157     if (IsStartFrameEventType(index)) {
158         StartAsyncTrace(HITRACE_TAG_GRAPHIC_AGP, GetAsyncNameByFrameEventType(index), currentFrameNumber_);
159     } else {
160         FinishAsyncTrace(HITRACE_TAG_GRAPHIC_AGP, GetAsyncNameByFrameEventType(index), currentFrameNumber_);
161     }
162 
163     if (index < uimarksEnd) {
164         pendingUIMarks_.times[index] = timeNs;
165         return true;
166     }
167 
168     // index == uimarksEnd
169     pendingUIMarks_.times[index] = timeNs;
170     currentUIMarks_ = pendingUIMarks_;
171     pendingUIMarks_.frameNumber = ++currentFrameNumber_;
172     return true;
173 }
174 
ClearEvents()175 void FrameCollector::ClearEvents()
176 {
177     std::lock_guard lock(frameQueueMutex_);
178     frameQueue_.Clear();
179 }
180 
FrameCollector()181 FrameCollector::FrameCollector()
182 {
183     char value[0x20];
184     GetParameter(switchRenderingText, "disable", value, sizeof(value));
185     SwitchFunction(switchRenderingText, value, this);
186     WatchParameter(switchRenderingText, SwitchFunction, this);
187 }
188 
SwitchFunction(const char * key,const char * value,void * context)189 void FrameCollector::SwitchFunction(const char *key, const char *value, void *context)
190 {
191     auto &that = *reinterpret_cast<FrameCollector *>(context);
192     auto oldEnable = that.enabled_;
193     std::string str = value;
194     if (str == switchRenderingPaintText) {
195         that.ClearEvents();
196         that.usingSaver_ = false;
197         that.enabled_ = true;
198     }
199 
200     if (str == switchRenderingSaverText) {
201         that.ClearEvents();
202         that.usingSaver_ = true;
203         that.enabled_ = false;
204         that.saver_ = std::make_unique<FrameSaver>();
205     }
206 
207     if (str == switchRenderingDisableText) {
208         that.usingSaver_ = false;
209         that.enabled_ = false;
210     }
211 
212     if (that.enabled_ != oldEnable && that.repaint_ != nullptr) {
213         that.repaint_();
214     }
215 }
216 } // namespace Rosen
217 } // namespace OHOS
218