169 lines
4.3 KiB
C++
169 lines
4.3 KiB
C++
/*
|
|
* Copyright (c) 2017 Amlogic, Inc. All rights reserved.
|
|
*
|
|
* This source code is subject to the terms and conditions defined in the
|
|
* file 'LICENSE' which is part of this source code package.
|
|
*
|
|
* Description:
|
|
*/
|
|
|
|
#include <drm.h>
|
|
#include <drm_fourcc.h>
|
|
#include <DrmSync.h>
|
|
#include <unistd.h>
|
|
#include <sync.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <MesonLog.h>
|
|
|
|
#ifdef __ANDROID__
|
|
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
|
|
#include <utils/Trace.h>
|
|
#endif
|
|
|
|
#define DRM_IOCTL_MESON_CREATE_FENCE DRM_IOWR(DRM_COMMAND_BASE + \
|
|
0x21, struct meson_drm_create_fence)
|
|
#define DRM_IOCTL_MESON_SIGNAL_FENCE DRM_IOWR(DRM_COMMAND_BASE + \
|
|
0x22, struct meson_drm_signal_fence)
|
|
|
|
typedef struct meson_drm_create_fence {
|
|
uint64_t context_id;
|
|
uint64_t seqno;
|
|
uint32_t fence_fd; /* out */
|
|
uint32_t flags;
|
|
} meson_drm_create_fence_t;
|
|
|
|
typedef struct meson_drm_signal_fence {
|
|
uint32_t fence_fd; /* in */
|
|
uint32_t flags;
|
|
} meson_drm_signal_fence_t;
|
|
|
|
const std::shared_ptr<DrmFence> DrmFence::NO_FENCE =
|
|
std::make_shared<DrmFence>(-1);
|
|
int32_t DrmFence::drmDevFd = -1;
|
|
|
|
DrmFence::DrmFence(int32_t fd) {
|
|
mFenceFd = fd;
|
|
}
|
|
|
|
DrmFence::~DrmFence() {
|
|
if (mFenceFd >= 0) {
|
|
close(mFenceFd);
|
|
mFenceFd = -1;
|
|
}
|
|
}
|
|
|
|
int32_t DrmFence::wait(int timeout) {
|
|
#ifdef __ANDROID__
|
|
ATRACE_CALL();
|
|
#endif
|
|
if (mFenceFd == -1) {
|
|
return 0;
|
|
}
|
|
int err = sync_wait(mFenceFd, timeout);
|
|
return err < 0 ? -errno : 0;
|
|
}
|
|
|
|
int32_t DrmFence::waitForever(const char* logname) {
|
|
#ifdef __ANDROID__
|
|
ATRACE_CALL();
|
|
#endif
|
|
if (mFenceFd == -1) {
|
|
return 0;
|
|
}
|
|
int warningTimeout = 3000;
|
|
int err = sync_wait(mFenceFd, warningTimeout);
|
|
if (err < 0 && errno == ETIME) {
|
|
MESON_LOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd,
|
|
warningTimeout);
|
|
err = sync_wait(mFenceFd, -1);
|
|
}
|
|
return err < 0 ? -errno : 0;
|
|
}
|
|
|
|
|
|
std::shared_ptr<DrmFence> DrmFence::merge(const char * name,
|
|
const std::shared_ptr<DrmFence> &f1,
|
|
const std::shared_ptr<DrmFence> &f2) {
|
|
|
|
int result;
|
|
// Merge the two fences. In the case where one of the fences is not a
|
|
// valid fence (e.g. NO_FENCE) we merge the one valid fence with itself so
|
|
// that a new fence with the given name is created.
|
|
if (f1->isValid() && f2->isValid()) {
|
|
result = sync_merge(name, f1->mFenceFd, f2->mFenceFd);
|
|
} else if (f1->isValid()) {
|
|
result = sync_merge(name, f1->mFenceFd, f1->mFenceFd);
|
|
} else if (f2->isValid()) {
|
|
result = sync_merge(name, f2->mFenceFd, f2->mFenceFd);
|
|
} else {
|
|
return NO_FENCE;
|
|
}
|
|
if (result == -1) {
|
|
int err = -errno;
|
|
MESON_LOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)",
|
|
name, f1->mFenceFd, f2->mFenceFd,
|
|
strerror(-err), err);
|
|
return NO_FENCE;
|
|
}
|
|
return std::shared_ptr<DrmFence>(new DrmFence(result));
|
|
}
|
|
|
|
int32_t DrmFence::dup() const{
|
|
if (-1 == mFenceFd) {
|
|
return -1;
|
|
}
|
|
|
|
int32_t dupFence = ::dup(mFenceFd);
|
|
if (dupFence < 0) {
|
|
MESON_LOGE("fence %d dup failed: %s! please check it immediately!",
|
|
mFenceFd, strerror(errno));
|
|
}
|
|
|
|
return dupFence;
|
|
}
|
|
|
|
/**
|
|
* Create a private fence.
|
|
*
|
|
* @param fence [out] File descriptor of the created fence on success
|
|
* @return 0 on success, negative error code on failure
|
|
*/
|
|
int32_t DrmFence::create_private_fence(int32_t &fence) {
|
|
meson_drm_create_fence_t drmFence;
|
|
drmFence.context_id = 0xFF;
|
|
drmFence.seqno = 0xFF;
|
|
auto ret = ioctl(drmDevFd, DRM_IOCTL_MESON_CREATE_FENCE, &drmFence);
|
|
if (ret) {
|
|
fence = -1;
|
|
MESON_LOGE("%s failed, ret: %d", __func__, ret);
|
|
} else {
|
|
fence = drmFence.fence_fd;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Signal a private fence to indicate completion.
|
|
*
|
|
* @param fence File descriptor of the fence to signal
|
|
* @return 0 on success, negative error code on failure
|
|
*/
|
|
int32_t DrmFence::signal_private_fence(int32_t fence) {
|
|
if (fence < 0) {
|
|
MESON_LOGV("%s is invalid!", __func__);
|
|
return -1;
|
|
}
|
|
meson_drm_signal_fence_t drmFence;
|
|
drmFence.fence_fd = fence;
|
|
auto ret = ioctl(drmDevFd, DRM_IOCTL_MESON_SIGNAL_FENCE, &drmFence);
|
|
if (ret) {
|
|
MESON_LOGE("%s failed, ret: %d, errno: %d", __func__, ret, errno);
|
|
}
|
|
|
|
return ret;
|
|
}
|