xref: /aosp_15_r20/frameworks/native/libs/ui/Fence.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2012 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #include <ui/Fence.h>
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "Fence"
20*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
21*38e8c45fSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
22*38e8c45fSAndroid Build Coastguard Worker 
23*38e8c45fSAndroid Build Coastguard Worker // We would eliminate the non-conforming zero-length array, but we can't since
24*38e8c45fSAndroid Build Coastguard Worker // this is effectively included from the Linux kernel
25*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic push
26*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wzero-length-array"
27*38e8c45fSAndroid Build Coastguard Worker #include <sync/sync.h>
28*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic pop
29*38e8c45fSAndroid Build Coastguard Worker 
30*38e8c45fSAndroid Build Coastguard Worker #include <sys/types.h>
31*38e8c45fSAndroid Build Coastguard Worker #include <unistd.h>
32*38e8c45fSAndroid Build Coastguard Worker #include <utils/Log.h>
33*38e8c45fSAndroid Build Coastguard Worker #include <utils/String8.h>
34*38e8c45fSAndroid Build Coastguard Worker #include <utils/Trace.h>
35*38e8c45fSAndroid Build Coastguard Worker 
36*38e8c45fSAndroid Build Coastguard Worker namespace android {
37*38e8c45fSAndroid Build Coastguard Worker 
38*38e8c45fSAndroid Build Coastguard Worker const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence);
39*38e8c45fSAndroid Build Coastguard Worker 
Fence(int fenceFd)40*38e8c45fSAndroid Build Coastguard Worker Fence::Fence(int fenceFd) :
41*38e8c45fSAndroid Build Coastguard Worker     mFenceFd(fenceFd) {
42*38e8c45fSAndroid Build Coastguard Worker }
43*38e8c45fSAndroid Build Coastguard Worker 
Fence(base::unique_fd fenceFd)44*38e8c45fSAndroid Build Coastguard Worker Fence::Fence(base::unique_fd fenceFd) :
45*38e8c45fSAndroid Build Coastguard Worker     mFenceFd(std::move(fenceFd)) {
46*38e8c45fSAndroid Build Coastguard Worker }
47*38e8c45fSAndroid Build Coastguard Worker 
wait(int timeout)48*38e8c45fSAndroid Build Coastguard Worker status_t Fence::wait(int timeout) {
49*38e8c45fSAndroid Build Coastguard Worker     ATRACE_CALL();
50*38e8c45fSAndroid Build Coastguard Worker     if (mFenceFd == -1) {
51*38e8c45fSAndroid Build Coastguard Worker         return NO_ERROR;
52*38e8c45fSAndroid Build Coastguard Worker     }
53*38e8c45fSAndroid Build Coastguard Worker     int err = sync_wait(mFenceFd, timeout);
54*38e8c45fSAndroid Build Coastguard Worker     return err < 0 ? -errno : status_t(NO_ERROR);
55*38e8c45fSAndroid Build Coastguard Worker }
56*38e8c45fSAndroid Build Coastguard Worker 
waitForever(const char * logname)57*38e8c45fSAndroid Build Coastguard Worker status_t Fence::waitForever(const char* logname) {
58*38e8c45fSAndroid Build Coastguard Worker     ATRACE_CALL();
59*38e8c45fSAndroid Build Coastguard Worker     if (mFenceFd == -1) {
60*38e8c45fSAndroid Build Coastguard Worker         return NO_ERROR;
61*38e8c45fSAndroid Build Coastguard Worker     }
62*38e8c45fSAndroid Build Coastguard Worker     int warningTimeout = 3000;
63*38e8c45fSAndroid Build Coastguard Worker     int err = sync_wait(mFenceFd, warningTimeout);
64*38e8c45fSAndroid Build Coastguard Worker     if (err < 0 && errno == ETIME) {
65*38e8c45fSAndroid Build Coastguard Worker         ALOGE("waitForever: %s: fence %d didn't signal in %u ms", logname, mFenceFd.get(),
66*38e8c45fSAndroid Build Coastguard Worker               warningTimeout);
67*38e8c45fSAndroid Build Coastguard Worker 
68*38e8c45fSAndroid Build Coastguard Worker         struct sync_file_info* finfo = sync_file_info(mFenceFd);
69*38e8c45fSAndroid Build Coastguard Worker         if (finfo) {
70*38e8c45fSAndroid Build Coastguard Worker             // status: active(0) signaled(1) error(<0)
71*38e8c45fSAndroid Build Coastguard Worker             ALOGI("waitForever: fence(%s) status(%d)", finfo->name, finfo->status);
72*38e8c45fSAndroid Build Coastguard Worker 
73*38e8c45fSAndroid Build Coastguard Worker             struct sync_fence_info* pinfo = sync_get_fence_info(finfo);
74*38e8c45fSAndroid Build Coastguard Worker             for (uint32_t i = 0; i < finfo->num_fences; i++) {
75*38e8c45fSAndroid Build Coastguard Worker                 uint64_t ts_sec = pinfo[i].timestamp_ns / 1000000000LL;
76*38e8c45fSAndroid Build Coastguard Worker                 uint64_t ts_usec = (pinfo[i].timestamp_ns % 1000000000LL) / 1000LL;
77*38e8c45fSAndroid Build Coastguard Worker 
78*38e8c45fSAndroid Build Coastguard Worker                 ALOGI("waitForever: sync point: timeline(%s) drv(%s) status(%d) timestamp(%" PRIu64
79*38e8c45fSAndroid Build Coastguard Worker                       ".%06" PRIu64 ")",
80*38e8c45fSAndroid Build Coastguard Worker                       pinfo[i].obj_name, pinfo[i].driver_name, pinfo[i].status, ts_sec, ts_usec);
81*38e8c45fSAndroid Build Coastguard Worker             }
82*38e8c45fSAndroid Build Coastguard Worker             sync_file_info_free(finfo);
83*38e8c45fSAndroid Build Coastguard Worker         }
84*38e8c45fSAndroid Build Coastguard Worker 
85*38e8c45fSAndroid Build Coastguard Worker         err = sync_wait(mFenceFd, TIMEOUT_NEVER);
86*38e8c45fSAndroid Build Coastguard Worker     }
87*38e8c45fSAndroid Build Coastguard Worker     return err < 0 ? -errno : status_t(NO_ERROR);
88*38e8c45fSAndroid Build Coastguard Worker }
89*38e8c45fSAndroid Build Coastguard Worker 
merge(const char * name,const sp<Fence> & f1,const sp<Fence> & f2)90*38e8c45fSAndroid Build Coastguard Worker sp<Fence> Fence::merge(const char* name, const sp<Fence>& f1,
91*38e8c45fSAndroid Build Coastguard Worker         const sp<Fence>& f2) {
92*38e8c45fSAndroid Build Coastguard Worker     ATRACE_CALL();
93*38e8c45fSAndroid Build Coastguard Worker     int result;
94*38e8c45fSAndroid Build Coastguard Worker     // Merge the two fences.  In the case where one of the fences is not a
95*38e8c45fSAndroid Build Coastguard Worker     // valid fence (e.g. NO_FENCE) we merge the one valid fence with itself so
96*38e8c45fSAndroid Build Coastguard Worker     // that a new fence with the given name is created.
97*38e8c45fSAndroid Build Coastguard Worker     if (f1->isValid() && f2->isValid()) {
98*38e8c45fSAndroid Build Coastguard Worker         result = sync_merge(name, f1->mFenceFd, f2->mFenceFd);
99*38e8c45fSAndroid Build Coastguard Worker     } else if (f1->isValid()) {
100*38e8c45fSAndroid Build Coastguard Worker         result = sync_merge(name, f1->mFenceFd, f1->mFenceFd);
101*38e8c45fSAndroid Build Coastguard Worker     } else if (f2->isValid()) {
102*38e8c45fSAndroid Build Coastguard Worker         result = sync_merge(name, f2->mFenceFd, f2->mFenceFd);
103*38e8c45fSAndroid Build Coastguard Worker     } else {
104*38e8c45fSAndroid Build Coastguard Worker         return NO_FENCE;
105*38e8c45fSAndroid Build Coastguard Worker     }
106*38e8c45fSAndroid Build Coastguard Worker     if (result == -1) {
107*38e8c45fSAndroid Build Coastguard Worker         status_t err = -errno;
108*38e8c45fSAndroid Build Coastguard Worker         ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)",
109*38e8c45fSAndroid Build Coastguard Worker                 name, f1->mFenceFd.get(), f2->mFenceFd.get(),
110*38e8c45fSAndroid Build Coastguard Worker                 strerror(-err), err);
111*38e8c45fSAndroid Build Coastguard Worker         return NO_FENCE;
112*38e8c45fSAndroid Build Coastguard Worker     }
113*38e8c45fSAndroid Build Coastguard Worker     return sp<Fence>(new Fence(result));
114*38e8c45fSAndroid Build Coastguard Worker }
115*38e8c45fSAndroid Build Coastguard Worker 
merge(const String8 & name,const sp<Fence> & f1,const sp<Fence> & f2)116*38e8c45fSAndroid Build Coastguard Worker sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1,
117*38e8c45fSAndroid Build Coastguard Worker         const sp<Fence>& f2) {
118*38e8c45fSAndroid Build Coastguard Worker     return merge(name.c_str(), f1, f2);
119*38e8c45fSAndroid Build Coastguard Worker }
120*38e8c45fSAndroid Build Coastguard Worker 
dup() const121*38e8c45fSAndroid Build Coastguard Worker int Fence::dup() const {
122*38e8c45fSAndroid Build Coastguard Worker     return ::dup(mFenceFd);
123*38e8c45fSAndroid Build Coastguard Worker }
124*38e8c45fSAndroid Build Coastguard Worker 
getSignalTime() const125*38e8c45fSAndroid Build Coastguard Worker nsecs_t Fence::getSignalTime() const {
126*38e8c45fSAndroid Build Coastguard Worker     if (mFenceFd == -1) {
127*38e8c45fSAndroid Build Coastguard Worker         return SIGNAL_TIME_INVALID;
128*38e8c45fSAndroid Build Coastguard Worker     }
129*38e8c45fSAndroid Build Coastguard Worker 
130*38e8c45fSAndroid Build Coastguard Worker     struct sync_file_info* finfo = sync_file_info(mFenceFd);
131*38e8c45fSAndroid Build Coastguard Worker     if (finfo == nullptr) {
132*38e8c45fSAndroid Build Coastguard Worker         ALOGE("sync_file_info returned NULL for fd %d", mFenceFd.get());
133*38e8c45fSAndroid Build Coastguard Worker         return SIGNAL_TIME_INVALID;
134*38e8c45fSAndroid Build Coastguard Worker     }
135*38e8c45fSAndroid Build Coastguard Worker 
136*38e8c45fSAndroid Build Coastguard Worker     if (finfo->status != 1) {
137*38e8c45fSAndroid Build Coastguard Worker         const auto status = finfo->status;
138*38e8c45fSAndroid Build Coastguard Worker         ALOGE_IF(status < 0, "%s: sync_file_info contains an error: <%d> for fd: <%d>", __func__,
139*38e8c45fSAndroid Build Coastguard Worker                  status, mFenceFd.get());
140*38e8c45fSAndroid Build Coastguard Worker         sync_file_info_free(finfo);
141*38e8c45fSAndroid Build Coastguard Worker         return status < 0 ? SIGNAL_TIME_INVALID : SIGNAL_TIME_PENDING;
142*38e8c45fSAndroid Build Coastguard Worker     }
143*38e8c45fSAndroid Build Coastguard Worker 
144*38e8c45fSAndroid Build Coastguard Worker     uint64_t timestamp = 0;
145*38e8c45fSAndroid Build Coastguard Worker     struct sync_fence_info* pinfo = sync_get_fence_info(finfo);
146*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 0; i < finfo->num_fences; i++) {
147*38e8c45fSAndroid Build Coastguard Worker         if (pinfo[i].timestamp_ns > timestamp) {
148*38e8c45fSAndroid Build Coastguard Worker             timestamp = pinfo[i].timestamp_ns;
149*38e8c45fSAndroid Build Coastguard Worker         }
150*38e8c45fSAndroid Build Coastguard Worker     }
151*38e8c45fSAndroid Build Coastguard Worker 
152*38e8c45fSAndroid Build Coastguard Worker     sync_file_info_free(finfo);
153*38e8c45fSAndroid Build Coastguard Worker     return nsecs_t(timestamp);
154*38e8c45fSAndroid Build Coastguard Worker }
155*38e8c45fSAndroid Build Coastguard Worker 
getFlattenedSize() const156*38e8c45fSAndroid Build Coastguard Worker size_t Fence::getFlattenedSize() const {
157*38e8c45fSAndroid Build Coastguard Worker     return 4;
158*38e8c45fSAndroid Build Coastguard Worker }
159*38e8c45fSAndroid Build Coastguard Worker 
getFdCount() const160*38e8c45fSAndroid Build Coastguard Worker size_t Fence::getFdCount() const {
161*38e8c45fSAndroid Build Coastguard Worker     return isValid() ? 1 : 0;
162*38e8c45fSAndroid Build Coastguard Worker }
163*38e8c45fSAndroid Build Coastguard Worker 
flatten(void * & buffer,size_t & size,int * & fds,size_t & count) const164*38e8c45fSAndroid Build Coastguard Worker status_t Fence::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
165*38e8c45fSAndroid Build Coastguard Worker     if (size < getFlattenedSize() || count < getFdCount()) {
166*38e8c45fSAndroid Build Coastguard Worker         return NO_MEMORY;
167*38e8c45fSAndroid Build Coastguard Worker     }
168*38e8c45fSAndroid Build Coastguard Worker     // Cast to uint32_t since the size of a size_t can vary between 32- and
169*38e8c45fSAndroid Build Coastguard Worker     // 64-bit processes
170*38e8c45fSAndroid Build Coastguard Worker     FlattenableUtils::write(buffer, size, static_cast<uint32_t>(getFdCount()));
171*38e8c45fSAndroid Build Coastguard Worker     if (isValid()) {
172*38e8c45fSAndroid Build Coastguard Worker         *fds++ = mFenceFd;
173*38e8c45fSAndroid Build Coastguard Worker         count--;
174*38e8c45fSAndroid Build Coastguard Worker     }
175*38e8c45fSAndroid Build Coastguard Worker     return NO_ERROR;
176*38e8c45fSAndroid Build Coastguard Worker }
177*38e8c45fSAndroid Build Coastguard Worker 
unflatten(void const * & buffer,size_t & size,int const * & fds,size_t & count)178*38e8c45fSAndroid Build Coastguard Worker status_t Fence::unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count) {
179*38e8c45fSAndroid Build Coastguard Worker     if (mFenceFd != -1) {
180*38e8c45fSAndroid Build Coastguard Worker         // Don't unflatten if we already have a valid fd.
181*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
182*38e8c45fSAndroid Build Coastguard Worker     }
183*38e8c45fSAndroid Build Coastguard Worker 
184*38e8c45fSAndroid Build Coastguard Worker     if (size < getFlattenedSize()) {
185*38e8c45fSAndroid Build Coastguard Worker         return NO_MEMORY;
186*38e8c45fSAndroid Build Coastguard Worker     }
187*38e8c45fSAndroid Build Coastguard Worker 
188*38e8c45fSAndroid Build Coastguard Worker     uint32_t numFds;
189*38e8c45fSAndroid Build Coastguard Worker     FlattenableUtils::read(buffer, size, numFds);
190*38e8c45fSAndroid Build Coastguard Worker 
191*38e8c45fSAndroid Build Coastguard Worker     if (numFds > 1) {
192*38e8c45fSAndroid Build Coastguard Worker         return BAD_VALUE;
193*38e8c45fSAndroid Build Coastguard Worker     }
194*38e8c45fSAndroid Build Coastguard Worker 
195*38e8c45fSAndroid Build Coastguard Worker     if (count < numFds) {
196*38e8c45fSAndroid Build Coastguard Worker         return NO_MEMORY;
197*38e8c45fSAndroid Build Coastguard Worker     }
198*38e8c45fSAndroid Build Coastguard Worker 
199*38e8c45fSAndroid Build Coastguard Worker     if (numFds) {
200*38e8c45fSAndroid Build Coastguard Worker         mFenceFd.reset(*fds++);
201*38e8c45fSAndroid Build Coastguard Worker         count--;
202*38e8c45fSAndroid Build Coastguard Worker     }
203*38e8c45fSAndroid Build Coastguard Worker 
204*38e8c45fSAndroid Build Coastguard Worker     return NO_ERROR;
205*38e8c45fSAndroid Build Coastguard Worker }
206*38e8c45fSAndroid Build Coastguard Worker 
207*38e8c45fSAndroid Build Coastguard Worker } // namespace android
208