1 /*
2 * Copyright (c) 2024 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 "drag_smooth_processor.h"
17
18 #include <utility>
19
20 #include "devicestatus_common.h"
21 #include "include/util.h"
22
23 #undef LOG_TAG
24 #define LOG_TAG "DragSmoothProcessor"
25
26 namespace OHOS {
27 namespace Msdp {
28 namespace DeviceStatus {
29 namespace {
30 constexpr uint64_t ONE_MS_IN_NS { 1 * 1000 * 1000 }; // 1ms
31 constexpr int32_t RESAMPLE_COORD_TIME_THRESHOLD { 20 * 1000 * 1000 }; // 20ms
32 constexpr uint64_t INTERPOLATION_THRESHOLD { 100 * 1000 * 1000 }; // 100ms
33 }
InsertEvent(const DragMoveEvent & event)34 void DragSmoothProcessor::InsertEvent(const DragMoveEvent &event)
35 {
36 std::lock_guard<std::mutex> lock(mtx_);
37 moveEvents_.emplace_back(event);
38 }
39
SmoothMoveEvent(uint64_t nanoTimestamp,uint64_t vSyncPeriod)40 DragMoveEvent DragSmoothProcessor::SmoothMoveEvent(uint64_t nanoTimestamp, uint64_t vSyncPeriod)
41 {
42 resampleTimeStamp_ = nanoTimestamp - vSyncPeriod + ONE_MS_IN_NS;
43 auto targetTimeStamp = resampleTimeStamp_;
44 std::vector<DragMoveEvent> currentEvents;
45 {
46 std::lock_guard<std::mutex> lock(mtx_);
47 currentEvents.swap(moveEvents_);
48 }
49 DragMoveEvent latestEvent = currentEvents.back();
50 auto resampleEvent = GetResampleEvent(historyEvents_, currentEvents, targetTimeStamp);
51 historyEvents_ = currentEvents;
52 return resampleEvent.has_value() ? resampleEvent.value() : latestEvent;
53 }
54
ResetParameters()55 void DragSmoothProcessor::ResetParameters()
56 {
57 std::lock_guard<std::mutex> lock(mtx_);
58 moveEvents_.clear();
59 historyEvents_.clear();
60 resampleTimeStamp_ = 0;
61 }
62
GetResampleEvent(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,uint64_t nanoTimestamp)63 std::optional<DragMoveEvent> DragSmoothProcessor::GetResampleEvent(const std::vector<DragMoveEvent>& history,
64 const std::vector<DragMoveEvent>& current, uint64_t nanoTimestamp)
65 {
66 auto event = Resample(history, current, nanoTimestamp);
67 DragMoveEvent nearestEvent = GetNearestEvent(current, nanoTimestamp);
68 return event.has_value() ? event.value() : nearestEvent;
69 }
70
GetNearestEvent(const std::vector<DragMoveEvent> & events,uint64_t nanoTimestamp)71 DragMoveEvent DragSmoothProcessor::GetNearestEvent(const std::vector<DragMoveEvent>& events, uint64_t nanoTimestamp)
72 {
73 DragMoveEvent nearestEvent;
74 uint64_t gap = UINT64_MAX;
75 for (const auto &event : events) {
76 if (event.timestamp == nanoTimestamp) {
77 nearestEvent = event;
78 return nearestEvent;
79 }
80 if (event.timestamp > nanoTimestamp) {
81 if (event.timestamp - nanoTimestamp < gap) {
82 gap = event.timestamp - nanoTimestamp;
83 nearestEvent = event;
84 }
85 } else {
86 if (nanoTimestamp - event.timestamp < gap) {
87 gap = nanoTimestamp - event.timestamp;
88 nearestEvent = event;
89 }
90 }
91 }
92 return nearestEvent;
93 }
94
Resample(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,uint64_t nanoTimestamp)95 std::optional<DragMoveEvent> DragSmoothProcessor::Resample(const std::vector<DragMoveEvent>& history,
96 const std::vector<DragMoveEvent>& current, uint64_t nanoTimestamp)
97 {
98 if (history.empty() || current.empty()) {
99 FI_HILOGW("history or current is empty, history size:%{public}zu, current size:%{public}zu,"
100 "nanoTimestamp:%{public}" PRId64, history.size(), current.size(), nanoTimestamp);
101 return std::nullopt;
102 }
103 DragMoveEvent latestEvent;
104 for (auto const &event : current) {
105 if (latestEvent.timestamp < event.timestamp) {
106 latestEvent = event;
107 }
108 }
109 if (nanoTimestamp > RESAMPLE_COORD_TIME_THRESHOLD + latestEvent.timestamp) {
110 FI_HILOGW("latestEvent is beyond the sampling range, use this this latest event, x:%{private}f, "
111 "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, sampling nanoTimestamp:%{public}" PRId64,
112 latestEvent.displayX, latestEvent.displayY, latestEvent.timestamp, latestEvent.displayId, nanoTimestamp);
113 return latestEvent;
114 }
115 auto historyAvgEvent = GetAvgCoordinate(history);
116 auto currentAvgEvent = GetAvgCoordinate(current);
117 DumpMoveEvent(history, current, historyAvgEvent, currentAvgEvent, latestEvent);
118 return GetInterpolatedEvent(historyAvgEvent, currentAvgEvent, nanoTimestamp);
119 }
120
GetInterpolatedEvent(const DragMoveEvent & historyAvgEvent,const DragMoveEvent & currentAvgEvent,uint64_t nanoTimestamp)121 std::optional<DragMoveEvent> DragSmoothProcessor::GetInterpolatedEvent(const DragMoveEvent &historyAvgEvent,
122 const DragMoveEvent ¤tAvgEvent, uint64_t nanoTimestamp)
123 {
124 if ((nanoTimestamp <= historyAvgEvent.timestamp) || (nanoTimestamp == currentAvgEvent.timestamp) ||
125 (currentAvgEvent.timestamp <= historyAvgEvent.timestamp) ||
126 ((currentAvgEvent.timestamp - historyAvgEvent.timestamp) > INTERPOLATION_THRESHOLD)) {
127 FI_HILOGW("No need linear interpolation, historyAvgEvent x:%{private}f, "
128 "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, currentAvgEvent x:%{private}f"
129 "y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d, nanoTimestamp: %{public}" PRId64,
130 historyAvgEvent.displayX, historyAvgEvent.displayY, historyAvgEvent.timestamp, historyAvgEvent.displayId,
131 currentAvgEvent.displayX, currentAvgEvent.displayY, currentAvgEvent.timestamp, currentAvgEvent.displayId,
132 nanoTimestamp);
133 return std::nullopt;
134 }
135 DragMoveEvent event;
136 if (nanoTimestamp < currentAvgEvent.timestamp) {
137 float alpha = static_cast<float>(nanoTimestamp - historyAvgEvent.timestamp) /
138 (currentAvgEvent.timestamp - historyAvgEvent.timestamp);
139 event.displayX = historyAvgEvent.displayX + alpha * (currentAvgEvent.displayX - historyAvgEvent.displayX);
140 event.displayY = historyAvgEvent.displayY + alpha * (currentAvgEvent.displayY - historyAvgEvent.displayY);
141 event.timestamp = nanoTimestamp;
142 event.displayId = currentAvgEvent.displayId;
143 } else if (nanoTimestamp > currentAvgEvent.timestamp) {
144 float alpha = static_cast<float>(nanoTimestamp - currentAvgEvent.timestamp) /
145 (currentAvgEvent.timestamp - historyAvgEvent.timestamp);
146 event.displayX = currentAvgEvent.displayX + alpha * (currentAvgEvent.displayX - historyAvgEvent.displayX);
147 event.displayY = currentAvgEvent.displayY + alpha * (currentAvgEvent.displayY - historyAvgEvent.displayY);
148 event.timestamp = nanoTimestamp;
149 event.displayId = currentAvgEvent.displayId;
150 }
151 return event;
152 }
153
DumpMoveEvent(const std::vector<DragMoveEvent> & history,const std::vector<DragMoveEvent> & current,const DragMoveEvent & historyAvgEvent,const DragMoveEvent & currentAvgEvent,const DragMoveEvent & latestEvent)154 void DragSmoothProcessor::DumpMoveEvent(const std::vector<DragMoveEvent>& history,
155 const std::vector<DragMoveEvent>& current, const DragMoveEvent &historyAvgEvent,
156 const DragMoveEvent ¤tAvgEvent, const DragMoveEvent &latestEvent)
157 {
158 for (const auto &event : history) {
159 FI_HILOGD("history event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
160 event.displayX, event.displayY, event.timestamp, event.displayId);
161 }
162 for (const auto &event : current) {
163 FI_HILOGD("current event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
164 event.displayX, event.displayY, event.timestamp, event.displayId);
165 }
166 FI_HILOGD("history average event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
167 historyAvgEvent.displayX, historyAvgEvent.displayY, historyAvgEvent.timestamp, historyAvgEvent.displayId);
168 FI_HILOGD("current average event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
169 currentAvgEvent.displayX, currentAvgEvent.displayY, currentAvgEvent.timestamp, currentAvgEvent.displayId);
170 FI_HILOGD("latest event, x:%{private}f, y:%{private}f, timestamp:%{public}" PRId64 "displayId:%{public}d",
171 latestEvent.displayX, latestEvent.displayY, latestEvent.timestamp, latestEvent.displayId);
172 }
173
GetAvgCoordinate(const std::vector<DragMoveEvent> & events)174 DragMoveEvent DragSmoothProcessor::GetAvgCoordinate(const std::vector<DragMoveEvent>& events)
175 {
176 DragMoveEvent avgEvent;
177 if (events.empty()) {
178 FI_HILOGW("events is empty");
179 return avgEvent;
180 }
181 int32_t i = 0;
182 uint64_t lastTime = 0;
183 for (const auto &event : events) {
184 if ((lastTime == 0) || (lastTime != event.timestamp)) {
185 avgEvent.displayX += event.displayX;
186 avgEvent.displayY += event.displayY;
187 avgEvent.timestamp += event.timestamp;
188 avgEvent.displayId = event.displayId;
189 lastTime = event.timestamp;
190 i++;
191 }
192 }
193 if (i != 0) {
194 avgEvent.displayX /= i;
195 avgEvent.displayY /= i;
196 avgEvent.timestamp /= static_cast<uint64_t>(i);
197 }
198 return avgEvent;
199 }
200 } // namespace DeviceStatus
201 } // namespace Msdp
202 } // namespace OHOS