| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| //#define LOG_NDEBUG 0 |
| #define LOG_TAG "C2FenceFactory" |
| #include <cutils/native_handle.h> |
| #include <utils/Log.h> |
| #include <ui/Fence.h> |
| |
| #include <C2FenceFactory.h> |
| #include <C2SurfaceSyncObj.h> |
| |
| #define MAX_FENCE_FDS 1 |
| |
| class C2Fence::Impl { |
| public: |
| enum type_t : uint32_t { |
| INVALID_FENCE, |
| NULL_FENCE, |
| SURFACE_FENCE, |
| SYNC_FENCE, |
| }; |
| |
| virtual c2_status_t wait(c2_nsecs_t timeoutNs) = 0; |
| |
| virtual bool valid() const = 0; |
| |
| virtual bool ready() const = 0; |
| |
| virtual int fd() const = 0; |
| |
| virtual bool isHW() const = 0; |
| |
| virtual type_t type() const = 0; |
| |
| /** |
| * Create a native handle for the fence so it can be marshalled. |
| * The native handle must store fence type in the first integer. |
| * |
| * \return a valid native handle if the fence can be marshalled, otherwise return null. |
| */ |
| virtual native_handle_t *createNativeHandle() const = 0; |
| |
| virtual ~Impl() = default; |
| |
| Impl() = default; |
| |
| static type_t GetTypeFromNativeHandle(const native_handle_t* nh) { |
| if (nh && nh->numFds >= 0 && nh->numFds <= MAX_FENCE_FDS && nh->numInts > 0) { |
| return static_cast<type_t>(nh->data[nh->numFds]); |
| } |
| return INVALID_FENCE; |
| } |
| }; |
| |
| c2_status_t C2Fence::wait(c2_nsecs_t timeoutNs) { |
| if (mImpl) { |
| return mImpl->wait(timeoutNs); |
| } |
| // null fence is always signalled. |
| return C2_OK; |
| } |
| |
| bool C2Fence::valid() const { |
| if (mImpl) { |
| return mImpl->valid(); |
| } |
| // null fence is always valid. |
| return true; |
| } |
| |
| bool C2Fence::ready() const { |
| if (mImpl) { |
| return mImpl->ready(); |
| } |
| // null fence is always signalled. |
| return true; |
| } |
| |
| int C2Fence::fd() const { |
| if (mImpl) { |
| return mImpl->fd(); |
| } |
| // null fence does not have fd. |
| return -1; |
| } |
| |
| bool C2Fence::isHW() const { |
| if (mImpl) { |
| return mImpl->isHW(); |
| } |
| return false; |
| } |
| |
| /** |
| * Fence implementation for C2BufferQueueBlockPool based block allocation. |
| * The implementation supports all C2Fence interface except fd(). |
| */ |
| class _C2FenceFactory::SurfaceFenceImpl: public C2Fence::Impl { |
| public: |
| virtual c2_status_t wait(c2_nsecs_t timeoutNs) { |
| if (mPtr) { |
| return mPtr->waitForChange(mWaitId, timeoutNs); |
| } |
| return C2_OK; |
| } |
| |
| virtual bool valid() const { |
| return mPtr; |
| } |
| |
| virtual bool ready() const { |
| uint32_t status; |
| if (mPtr) { |
| mPtr->lock(); |
| status = mPtr->getWaitIdLocked(); |
| mPtr->unlock(); |
| |
| return status != mWaitId; |
| } |
| return true; |
| } |
| |
| virtual int fd() const { |
| // does not support fd, since this is shared mem and futex based |
| return -1; |
| } |
| |
| virtual bool isHW() const { |
| return false; |
| } |
| |
| virtual type_t type() const { |
| return SURFACE_FENCE; |
| } |
| |
| virtual native_handle_t *createNativeHandle() const { |
| ALOGD("Cannot create native handle from surface fence"); |
| return nullptr; |
| } |
| |
| virtual ~SurfaceFenceImpl() {}; |
| |
| SurfaceFenceImpl(std::shared_ptr<C2SurfaceSyncMemory> syncMem, uint32_t waitId) : |
| mSyncMem(syncMem), |
| mPtr(syncMem ? syncMem->mem() : nullptr), |
| mWaitId(syncMem ? waitId : 0) {} |
| private: |
| const std::shared_ptr<const C2SurfaceSyncMemory> mSyncMem; // This is for life-cycle guarantee |
| C2SyncVariables *const mPtr; |
| const uint32_t mWaitId; |
| }; |
| |
| C2Fence::C2Fence(std::shared_ptr<Impl> impl) : mImpl(impl) {} |
| |
| C2Fence _C2FenceFactory::CreateSurfaceFence( |
| std::shared_ptr<C2SurfaceSyncMemory> syncMem, |
| uint32_t waitId) { |
| if (syncMem) { |
| C2Fence::Impl *p |
| = new _C2FenceFactory::SurfaceFenceImpl(syncMem, waitId); |
| if (p->valid()) { |
| return C2Fence(std::shared_ptr<C2Fence::Impl>(p)); |
| } else { |
| delete p; |
| } |
| } |
| return C2Fence(); |
| } |
| |
| using namespace android; |
| |
| class _C2FenceFactory::SyncFenceImpl : public C2Fence::Impl { |
| public: |
| virtual c2_status_t wait(c2_nsecs_t timeoutNs) { |
| c2_nsecs_t timeoutMs = timeoutNs / 1000; |
| if (timeoutMs > INT_MAX) { |
| timeoutMs = INT_MAX; |
| } |
| |
| switch (mFence->wait((int)timeoutMs)) { |
| case NO_ERROR: |
| return C2_OK; |
| case -ETIME: |
| return C2_TIMED_OUT; |
| default: |
| return C2_CORRUPTED; |
| } |
| } |
| |
| virtual bool valid() const { |
| return mFence->getStatus() != Fence::Status::Invalid; |
| } |
| |
| virtual bool ready() const { |
| return mFence->getStatus() == Fence::Status::Signaled; |
| } |
| |
| virtual int fd() const { |
| return mFence->dup(); |
| } |
| |
| virtual bool isHW() const { |
| return true; |
| } |
| |
| virtual type_t type() const { |
| return SYNC_FENCE; |
| } |
| |
| virtual native_handle_t *createNativeHandle() const { |
| native_handle_t* nh = native_handle_create(1, 1); |
| if (!nh) { |
| ALOGE("Failed to allocate native handle for sync fence"); |
| return nullptr; |
| } |
| nh->data[0] = fd(); |
| nh->data[1] = type(); |
| return nh; |
| } |
| |
| virtual ~SyncFenceImpl() {}; |
| |
| SyncFenceImpl(int fenceFd) : |
| mFence(sp<Fence>::make(fenceFd)) {} |
| |
| static std::shared_ptr<SyncFenceImpl> CreateFromNativeHandle(const native_handle_t* nh) { |
| if (!nh || nh->numFds != 1 || nh->numInts != 1) { |
| ALOGE("Invalid handle for sync fence"); |
| return nullptr; |
| } |
| int fd = dup(nh->data[0]); |
| std::shared_ptr<SyncFenceImpl> p = std::make_shared<SyncFenceImpl>(fd); |
| if (!p) { |
| ALOGE("Failed to allocate sync fence impl"); |
| close(fd); |
| } |
| return p; |
| } |
| |
| private: |
| const sp<Fence> mFence; |
| }; |
| |
| C2Fence _C2FenceFactory::CreateSyncFence(int fenceFd) { |
| std::shared_ptr<C2Fence::Impl> p; |
| if (fenceFd >= 0) { |
| p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fenceFd); |
| if (!p) { |
| ALOGE("Failed to allocate sync fence impl"); |
| close(fenceFd); |
| } |
| if (!p->valid()) { |
| p.reset(); |
| } |
| } else { |
| ALOGE("Create sync fence from invalid fd"); |
| } |
| return C2Fence(p); |
| } |
| |
| native_handle_t* _C2FenceFactory::CreateNativeHandle(const C2Fence& fence) { |
| return fence.mImpl? fence.mImpl->createNativeHandle() : nullptr; |
| } |
| |
| C2Fence _C2FenceFactory::CreateFromNativeHandle(const native_handle_t* handle) { |
| if (!handle) { |
| return C2Fence(); |
| } |
| C2Fence::Impl::type_t type = C2Fence::Impl::GetTypeFromNativeHandle(handle); |
| std::shared_ptr<C2Fence::Impl> p; |
| switch (type) { |
| case C2Fence::Impl::SYNC_FENCE: |
| p = SyncFenceImpl::CreateFromNativeHandle(handle); |
| break; |
| default: |
| ALOGD("Unsupported fence type %d", type); |
| // return a null-fence in this case |
| break; |
| } |
| if (p && !p->valid()) { |
| p.reset(); |
| } |
| return C2Fence(p); |
| } |
| |