/* * 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 #include #include #include #include #include #include #include #include #ifdef __ANDROID__ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #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::NO_FENCE = std::make_shared(-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::merge(const char * name, const std::shared_ptr &f1, const std::shared_ptr &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 && f1->isValid() && f2 && f2->isValid()) { result = sync_merge(name, f1->mFenceFd, f2->mFenceFd); } else if (f1 && f1->isValid()) { int fd1 = f1->mFenceFd; result = sync_merge(name, fd1 , fd1); } else if (f2 && f2->isValid()) { int fd2 = f2->mFenceFd; result = sync_merge(name, fd2, fd2); } else { return NO_FENCE; } if (result == -1) { int err = -errno; MESON_LOGE("merge: sync_merge(\"%s\") returned an error: %s (%d)", name, strerror(-err), err); return NO_FENCE; } return std::shared_ptr(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; }