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 "vsync_receiver.h"
17 #include <memory>
18 #include <mutex>
19 #include <unistd.h>
20 #include <scoped_bytrace.h>
21 #include <fcntl.h>
22 #include <hitrace_meter.h>
23 #if defined(RS_ENABLE_DVSYNC_2)
24 #include "dvsync_delay.h"
25 #endif
26 #include "graphic_common.h"
27 #include "rs_frame_report_ext.h"
28 #include "vsync_log.h"
29 #include <rs_trace.h>
30
31 namespace OHOS {
32 namespace Rosen {
OnReadable(int32_t fileDescriptor)33 void VSyncCallBackListener::OnReadable(int32_t fileDescriptor)
34 {
35 HitracePerfScoped perfTrace(ScopedDebugTrace::isEnabled(), HITRACE_TAG_GRAPHIC_AGP, "OnReadablePerfCount");
36 {
37 std::lock_guard<std::mutex> locker(cbMutex_);
38 if (fileDescriptor < 0 || (readableCallback_ != nullptr && !readableCallback_(fileDescriptor))) {
39 VLOGE("OnReadable Invalid fileDescriptor:%{public}d", fileDescriptor);
40 return;
41 }
42 }
43 // 3 is array size.
44 int64_t data[3];
45 ssize_t dataCount = 0;
46 if (ReadFdInternal(fileDescriptor, data, dataCount) != VSYNC_ERROR_OK) {
47 return;
48 }
49 #if defined(RS_ENABLE_DVSYNC_2)
50 auto taskFunc = [now = data[0], period = data[1], vsyncId = data[2],
51 dataCount, fileDescriptor, weak = weak_from_this()]() {
52 if (auto self = weak.lock()) {
53 int64_t newData[3] = {now, period, vsyncId};
54 DVSyncDelay::Instance().UpdateDelayInfo();
55 self->HandleVsyncCallbacks(newData, dataCount, fileDescriptor);
56 } else {
57 VLOGE("VSyncCallBackListener::OnReadable, weak.lock error");
58 }
59 };
60 DVSyncDelay::Instance().ToDelay(taskFunc, name_, fileDescriptor);
61 #else
62 HandleVsyncCallbacks(data, dataCount, fileDescriptor);
63 #endif
64 }
65
OnShutdown(int32_t fileDescriptor)66 void VSyncCallBackListener::OnShutdown(int32_t fileDescriptor)
67 {
68 VLOGI("OnShutdown, fileDescriptor:%{public}d", fileDescriptor);
69 std::lock_guard<std::mutex> locker(cbMutex_);
70 if (fdShutDownCallback_ != nullptr) {
71 fdShutDownCallback_(fileDescriptor);
72 }
73 }
74
ReadFdInternal(int32_t fd,int64_t (& data)[3],ssize_t & dataCount)75 VsyncError VSyncCallBackListener::ReadFdInternal(int32_t fd, int64_t (&data)[3], ssize_t &dataCount)
76 {
77 std::lock_guard<std::mutex> locker(fdMutex_);
78 if (fdClosed_) {
79 return VSYNC_ERROR_API_FAILED;
80 }
81 ssize_t ret = 0;
82 do {
83 // only take the latest timestamp
84 ret = read(fd, data, sizeof(data));
85 if (ret == 0) {
86 VLOGE("ReadFdInternal, ret is 0, read fd:%{public}d failed, errno:%{public}d", fd, errno);
87 return VSYNC_ERROR_OK;
88 }
89 if (ret == -1) {
90 if (errno == EINTR) {
91 ret = 0;
92 continue;
93 } else if (errno != EAGAIN) {
94 VLOGE("ReadFdInternal, read fd:%{public}d failed, errno:%{public}d", fd, errno);
95 }
96 } else {
97 dataCount += ret;
98 }
99 } while (ret != -1);
100
101 return VSYNC_ERROR_OK;
102 }
103
HandleVsyncCallbacks(int64_t data[],ssize_t dataCount,int32_t fileDescriptor)104 void VSyncCallBackListener::HandleVsyncCallbacks(int64_t data[], ssize_t dataCount, int32_t fileDescriptor)
105 {
106 VSyncCallback cb = nullptr;
107 VSyncCallbackWithId cbWithId = nullptr;
108 void *userData = nullptr;
109 int64_t now = 0;
110 int64_t expectedEnd = 0;
111 std::vector<FrameCallback> callbacks;
112 {
113 std::lock_guard<std::mutex> locker(mtx_);
114 cb = vsyncCallbacks_;
115 cbWithId = vsyncCallbacksWithId_;
116 userData = userData_;
117 RNVFlag_ = false;
118 now = data[0];
119 period_ = data[1];
120 periodShared_ = data[1];
121 timeStamp_ = data[0];
122 timeStampShared_ = data[0];
123 expectedEnd = CalculateExpectedEndLocked(now);
124 callbacks = frameCallbacks_;
125 frameCallbacks_.clear();
126 }
127
128 VLOGD("dataCount:%{public}d, cb == nullptr:%{public}d", dataCount, (cb == nullptr));
129 // 1, 2: index of array data.
130 RS_TRACE_NAME_FMT("ReceiveVsync name:%s dataCount: %ldbytes now: %ld expectedEnd: %ld vsyncId: %ld, fd:%d",
131 name_.c_str(), dataCount, now, expectedEnd, data[2], fileDescriptor); // data[2] is vsyncId
132 if (callbacks.empty() && dataCount > 0 && (cbWithId != nullptr || cb != nullptr)) {
133 // data[2] is frameCount
134 cbWithId != nullptr ? cbWithId(now, data[2], userData) : cb(now, userData);
135 }
136 for (const auto& cb : callbacks) {
137 if (cb.callback_ != nullptr) {
138 cb.callback_(now, cb.userData_);
139 } else if (cb.callbackWithId_ != nullptr) {
140 cb.callbackWithId_(now, data[2], cb.userData_); // data[2] is vsyncId
141 }
142 }
143 if (OHOS::Rosen::RsFrameReportExt::GetInstance().GetEnable()) {
144 OHOS::Rosen::RsFrameReportExt::GetInstance().ReceiveVSync();
145 }
146 }
147
CalculateExpectedEndLocked(int64_t now)148 int64_t VSyncCallBackListener::CalculateExpectedEndLocked(int64_t now)
149 {
150 int64_t expectedEnd = 0;
151 if (period_ < 0 || now < period_ || now > INT64_MAX - period_) {
152 RS_TRACE_NAME_FMT("invalid timestamps, now:%ld, period_:%ld", now, period_);
153 VLOGE("invalid timestamps, now:" VPUBI64 ", period_:" VPUBI64, now, period_);
154 return 0;
155 }
156 expectedEnd = now + period_;
157 if (name_ == "rs") {
158 // rs vsync offset is 5000000ns
159 expectedEnd = expectedEnd + period_ - 5000000;
160 }
161 return expectedEnd;
162 }
163
SetFdClosedFlagLocked(bool fdClosed)164 void VSyncCallBackListener::SetFdClosedFlagLocked(bool fdClosed)
165 {
166 fdClosed_ = fdClosed;
167 }
168
RegisterFdShutDownCallback(FdShutDownCallback cb)169 void VSyncCallBackListener::RegisterFdShutDownCallback(FdShutDownCallback cb)
170 {
171 std::lock_guard<std::mutex> locker(cbMutex_);
172 fdShutDownCallback_ = cb;
173 }
174
RegisterReadableCallback(ReadableCallback cb)175 void VSyncCallBackListener::RegisterReadableCallback(ReadableCallback cb)
176 {
177 std::lock_guard<std::mutex> locker(cbMutex_);
178 readableCallback_ = cb;
179 }
180 } // namespace Rosen
181 } // namespace OHOS
182