android13/frameworks/av/media/codec2/vndk/C2Fence.cpp

300 lines
7.5 KiB
C++

/*
* 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);
}