1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "C2FenceFactory"
19 #include <cutils/native_handle.h>
20 #include <utils/Log.h>
21 #include <ui/Fence.h>
22
23 #include <C2FenceFactory.h>
24 #include <C2SurfaceSyncObj.h>
25
26 #define MAX_FENCE_FDS 1
27
28 class C2Fence::Impl {
29 public:
30 enum type_t : uint32_t {
31 INVALID_FENCE,
32 NULL_FENCE,
33 SURFACE_FENCE,
34 SYNC_FENCE,
35 };
36
37 virtual c2_status_t wait(c2_nsecs_t timeoutNs) = 0;
38
39 virtual bool valid() const = 0;
40
41 virtual bool ready() const = 0;
42
43 virtual int fd() const = 0;
44
45 virtual bool isHW() const = 0;
46
47 virtual type_t type() const = 0;
48
49 /**
50 * Create a native handle for the fence so it can be marshalled.
51 * The native handle must store fence type in the first integer.
52 *
53 * \return a valid native handle if the fence can be marshalled, otherwise return null.
54 */
55 virtual native_handle_t *createNativeHandle() const = 0;
56
57 virtual ~Impl() = default;
58
59 Impl() = default;
60
GetTypeFromNativeHandle(const native_handle_t * nh)61 static type_t GetTypeFromNativeHandle(const native_handle_t* nh) {
62 if (nh && nh->numFds >= 0 && nh->numFds <= MAX_FENCE_FDS && nh->numInts > 0) {
63 return static_cast<type_t>(nh->data[nh->numFds]);
64 }
65 return INVALID_FENCE;
66 }
67 };
68
wait(c2_nsecs_t timeoutNs)69 c2_status_t C2Fence::wait(c2_nsecs_t timeoutNs) {
70 if (mImpl) {
71 return mImpl->wait(timeoutNs);
72 }
73 // null fence is always signalled.
74 return C2_OK;
75 }
76
valid() const77 bool C2Fence::valid() const {
78 if (mImpl) {
79 return mImpl->valid();
80 }
81 // null fence is always valid.
82 return true;
83 }
84
ready() const85 bool C2Fence::ready() const {
86 if (mImpl) {
87 return mImpl->ready();
88 }
89 // null fence is always signalled.
90 return true;
91 }
92
fd() const93 int C2Fence::fd() const {
94 if (mImpl) {
95 return mImpl->fd();
96 }
97 // null fence does not have fd.
98 return -1;
99 }
100
isHW() const101 bool C2Fence::isHW() const {
102 if (mImpl) {
103 return mImpl->isHW();
104 }
105 return false;
106 }
107
108 /**
109 * Fence implementation for C2BufferQueueBlockPool based block allocation.
110 * The implementation supports all C2Fence interface except fd().
111 */
112 class _C2FenceFactory::SurfaceFenceImpl: public C2Fence::Impl {
113 public:
wait(c2_nsecs_t timeoutNs)114 virtual c2_status_t wait(c2_nsecs_t timeoutNs) {
115 if (mPtr) {
116 return mPtr->waitForChange(mWaitId, timeoutNs);
117 }
118 return C2_OK;
119 }
120
valid() const121 virtual bool valid() const {
122 return mPtr;
123 }
124
ready() const125 virtual bool ready() const {
126 uint32_t status;
127 if (mPtr) {
128 mPtr->lock();
129 status = mPtr->getWaitIdLocked();
130 mPtr->unlock();
131
132 return status != mWaitId;
133 }
134 return true;
135 }
136
fd() const137 virtual int fd() const {
138 // does not support fd, since this is shared mem and futex based
139 return -1;
140 }
141
isHW() const142 virtual bool isHW() const {
143 return false;
144 }
145
type() const146 virtual type_t type() const {
147 return SURFACE_FENCE;
148 }
149
createNativeHandle() const150 virtual native_handle_t *createNativeHandle() const {
151 ALOGD("Cannot create native handle from surface fence");
152 return nullptr;
153 }
154
~SurfaceFenceImpl()155 virtual ~SurfaceFenceImpl() {};
156
SurfaceFenceImpl(std::shared_ptr<C2SurfaceSyncMemory> syncMem,uint32_t waitId)157 SurfaceFenceImpl(std::shared_ptr<C2SurfaceSyncMemory> syncMem, uint32_t waitId) :
158 mSyncMem(syncMem),
159 mPtr(syncMem ? syncMem->mem() : nullptr),
160 mWaitId(syncMem ? waitId : 0) {}
161 private:
162 const std::shared_ptr<const C2SurfaceSyncMemory> mSyncMem; // This is for life-cycle guarantee
163 C2SyncVariables *const mPtr;
164 const uint32_t mWaitId;
165 };
166
C2Fence(std::shared_ptr<Impl> impl)167 C2Fence::C2Fence(std::shared_ptr<Impl> impl) : mImpl(impl) {}
168
CreateSurfaceFence(std::shared_ptr<C2SurfaceSyncMemory> syncMem,uint32_t waitId)169 C2Fence _C2FenceFactory::CreateSurfaceFence(
170 std::shared_ptr<C2SurfaceSyncMemory> syncMem,
171 uint32_t waitId) {
172 if (syncMem) {
173 C2Fence::Impl *p
174 = new _C2FenceFactory::SurfaceFenceImpl(syncMem, waitId);
175 if (p->valid()) {
176 return C2Fence(std::shared_ptr<C2Fence::Impl>(p));
177 } else {
178 delete p;
179 }
180 }
181 return C2Fence();
182 }
183
184 using namespace android;
185
186 class _C2FenceFactory::SyncFenceImpl : public C2Fence::Impl {
187 public:
wait(c2_nsecs_t timeoutNs)188 virtual c2_status_t wait(c2_nsecs_t timeoutNs) {
189 int64_t timeoutMs = timeoutNs / 1000000;
190 if (timeoutMs > INT_MAX) {
191 timeoutMs = INT_MAX;
192 }
193
194 switch (mFence->wait((int)timeoutMs)) {
195 case NO_ERROR:
196 return C2_OK;
197 case -ETIME:
198 return C2_TIMED_OUT;
199 default:
200 return C2_CORRUPTED;
201 }
202 }
203
valid() const204 virtual bool valid() const {
205 return mFence->getStatus() != Fence::Status::Invalid;
206 }
207
ready() const208 virtual bool ready() const {
209 return mFence->getStatus() == Fence::Status::Signaled;
210 }
211
fd() const212 virtual int fd() const {
213 return mFence->dup();
214 }
215
isHW() const216 virtual bool isHW() const {
217 return true;
218 }
219
type() const220 virtual type_t type() const {
221 return SYNC_FENCE;
222 }
223
createNativeHandle() const224 virtual native_handle_t *createNativeHandle() const {
225 native_handle_t* nh = native_handle_create(1, 1);
226 if (!nh) {
227 ALOGE("Failed to allocate native handle for sync fence");
228 return nullptr;
229 }
230 nh->data[0] = fd();
231 nh->data[1] = type();
232 return nh;
233 }
234
~SyncFenceImpl()235 virtual ~SyncFenceImpl() {};
236
SyncFenceImpl(int fenceFd)237 SyncFenceImpl(int fenceFd) :
238 mFence(sp<Fence>::make(fenceFd)) {}
239
CreateFromNativeHandle(const native_handle_t * nh)240 static std::shared_ptr<SyncFenceImpl> CreateFromNativeHandle(const native_handle_t* nh) {
241 if (!nh || nh->numFds != 1 || nh->numInts != 1) {
242 ALOGE("Invalid handle for sync fence");
243 return nullptr;
244 }
245 int fd = dup(nh->data[0]);
246 std::shared_ptr<SyncFenceImpl> p = std::make_shared<SyncFenceImpl>(fd);
247 if (!p) {
248 ALOGE("Failed to allocate sync fence impl");
249 close(fd);
250 }
251 return p;
252 }
253
254 private:
255 const sp<Fence> mFence;
256 };
257
CreateSyncFence(int fenceFd)258 C2Fence _C2FenceFactory::CreateSyncFence(int fenceFd) {
259 std::shared_ptr<C2Fence::Impl> p;
260 if (fenceFd >= 0) {
261 p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fenceFd);
262 if (!p) {
263 ALOGE("Failed to allocate sync fence impl");
264 close(fenceFd);
265 }
266 if (!p->valid()) {
267 p.reset();
268 }
269 } else {
270 ALOGE("Create sync fence from invalid fd");
271 }
272 return C2Fence(p);
273 }
274
CreateNativeHandle(const C2Fence & fence)275 native_handle_t* _C2FenceFactory::CreateNativeHandle(const C2Fence& fence) {
276 return fence.mImpl? fence.mImpl->createNativeHandle() : nullptr;
277 }
278
CreateFromNativeHandle(const native_handle_t * handle)279 C2Fence _C2FenceFactory::CreateFromNativeHandle(const native_handle_t* handle) {
280 if (!handle) {
281 return C2Fence();
282 }
283 C2Fence::Impl::type_t type = C2Fence::Impl::GetTypeFromNativeHandle(handle);
284 std::shared_ptr<C2Fence::Impl> p;
285 switch (type) {
286 case C2Fence::Impl::SYNC_FENCE:
287 p = SyncFenceImpl::CreateFromNativeHandle(handle);
288 break;
289 default:
290 ALOGD("Unsupported fence type %d", type);
291 // return a null-fence in this case
292 break;
293 }
294 if (p && !p->valid()) {
295 p.reset();
296 }
297 return C2Fence(p);
298 }
299
300