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