• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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