diff options
-rw-r--r-- | libhwc2.1/libdevice/ExynosDisplay.cpp | 5 | ||||
-rw-r--r-- | libhwc2.1/libdevice/ExynosDisplay.h | 2 | ||||
-rw-r--r-- | libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp | 117 | ||||
-rw-r--r-- | libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h | 61 | ||||
-rw-r--r-- | libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h | 1 |
5 files changed, 101 insertions, 85 deletions
diff --git a/libhwc2.1/libdevice/ExynosDisplay.cpp b/libhwc2.1/libdevice/ExynosDisplay.cpp index e615e63..6f50307 100644 --- a/libhwc2.1/libdevice/ExynosDisplay.cpp +++ b/libhwc2.1/libdevice/ExynosDisplay.cpp @@ -508,6 +508,8 @@ int32_t ExynosDisplay::destroyLayer(hwc2_layer_t outLayer) { setGeometryChanged(GEOMETRY_DISPLAY_LAYER_REMOVED); } + mDisplayInterface->destroyLayer(layer); + delete layer; if (mPlugState == false) { @@ -1244,6 +1246,7 @@ int32_t ExynosDisplay::configureHandle(ExynosLayer &layer, int fence_fd, exynos_ h -= crop; } + cfg.layer = &layer; if ((layer.mExynosCompositionType == HWC2_COMPOSITION_DEVICE) && (layer.mCompositionType == HWC2_COMPOSITION_CURSOR)) cfg.state = cfg.WIN_STATE_CURSOR; @@ -1276,6 +1279,7 @@ int32_t ExynosDisplay::configureHandle(ExynosLayer &layer, int fence_fd, exynos_ else cfg.format = layer.mPreprocessedInfo.mPrivateFormat; + cfg.buffer_id = gmeta.unique_id; cfg.fd_idma[0] = gmeta.fd; cfg.fd_idma[1] = gmeta.fd1; cfg.fd_idma[2] = gmeta.fd2; @@ -1509,6 +1513,7 @@ int32_t ExynosDisplay::configureOverlay(ExynosCompositionInfo &compositionInfo) } } + config.buffer_id = gmeta.unique_id; config.fd_idma[0] = gmeta.fd; config.fd_idma[1] = gmeta.fd1; config.fd_idma[2] = gmeta.fd2; diff --git a/libhwc2.1/libdevice/ExynosDisplay.h b/libhwc2.1/libdevice/ExynosDisplay.h index 03fbe18..6e83dd9 100644 --- a/libhwc2.1/libdevice/ExynosDisplay.h +++ b/libhwc2.1/libdevice/ExynosDisplay.h @@ -158,6 +158,8 @@ struct exynos_win_config_data } state = WIN_STATE_DISABLED; uint32_t color = 0; + const ExynosLayer* layer = nullptr; + uint64_t buffer_id = 0; int fd_idma[3] = {-1, -1, -1}; int acq_fence = -1; int rel_fence = -1; diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp index 7ebd1a0..54b7060 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp +++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp @@ -63,7 +63,7 @@ FramebufferManager::~FramebufferManager() Mutex::Autolock lock(mMutex); mRmFBThreadRunning = false; } - mCondition.signal(); + mFlipDone.signal(); mRmFBThread.join(); } @@ -81,7 +81,7 @@ uint32_t FramebufferManager::getBufHandleFromFd(int fd) int ret = drmPrimeFDToHandle(mDrmFd, fd, &gem_handle); if (ret) { - ALOGE("drmPrimeFDToHandle failed with error %d", ret); + ALOGE("drmPrimeFDToHandle failed with fd %d error %d", fd, ret); } return gem_handle; } @@ -98,13 +98,13 @@ int FramebufferManager::addFB2WithModifiers(uint32_t width, uint32_t height, uin return ret; } -void FramebufferManager::cleanup(FBList &cleanupBuffers) { - for (auto it = mCachedBuffers.begin(); - mCachedBuffers.size() > MAX_CACHED_BUFFERS && it != mCachedBuffers.end();) { - auto const cit = it++; - /* Can't remove framebuffer in active commit */ - if ((*cit)->lastLookupTime != mLastActiveCommitTime) { - cleanupBuffers.splice(cleanupBuffers.end(), mCachedBuffers, cit); +void FramebufferManager::cleanup(const ExynosLayer *layer) { + ATRACE_CALL(); + { + Mutex::Autolock lock(mMutex); + if (auto it = mCachedLayerBuffers.find(layer); it != mCachedLayerBuffers.end()) { + mCleanBuffers.splice(mCleanBuffers.end(), std::move(it->second)); + mCachedLayerBuffers.erase(it); } } } @@ -118,17 +118,15 @@ void FramebufferManager::removeFBsThreadRoutine() if (!mRmFBThreadRunning) { break; } - mCondition.wait(mMutex); - cleanup(cleanupBuffers); + mFlipDone.wait(mMutex); + cleanupBuffers.splice(cleanupBuffers.end(), mCleanBuffers); } ATRACE_NAME("cleanup framebuffers"); cleanupBuffers.clear(); } } -int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint32_t &fbId, - bool caching) -{ +int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint32_t &fbId) { int ret = NO_ERROR; int drmFormat = DRM_FORMAT_UNDEFINED; uint32_t bpp = 0; @@ -196,6 +194,25 @@ int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint } } + { + Mutex::Autolock lock(mMutex); + auto &cachedBuffers = mCachedLayerBuffers[config.layer]; + auto it = std::find_if(cachedBuffers.begin(), cachedBuffers.end(), + [&config](auto &buffer) { + return (buffer->buffer_id == config.buffer_id); + }); + if (it != cachedBuffers.end()) { + if (CC_LIKELY(config.fd_idma[0] == (*it)->fd)) { + fbId = (*it)->fbId; + return NO_ERROR; + } else { + ALOGE("Framebuffer: found mismatch record fd %d vs %d with buffer id %" PRIu64, + config.fd_idma[0], (*it)->fd, (*it)->buffer_id); + cachedBuffers.erase(it); + } + } + } + for (uint32_t bufferIndex = 0; bufferIndex < bufferNum; bufferIndex++) { pitches[bufferIndex] = config.src.f_w * bpp; modifiers[bufferIndex] = modifiers[0]; @@ -220,30 +237,22 @@ int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint bufHeight = config.dst.h; modifiers[0] |= DRM_FORMAT_MOD_SAMSUNG_COLORMAP; drmFormat = DRM_FORMAT_BGRA8888; + bufferNum = 0; handles[0] = 0xff000000; bpp = getBytePerPixelOfPrimaryPlane(HAL_PIXEL_FORMAT_BGRA_8888); pitches[0] = config.dst.w * bpp; - caching = false; } else { ALOGE("%s:: known config state(%d)", __func__, config.state); return -EINVAL; } - if (caching) { - Mutex::Autolock lock(mMutex); - auto it = - std::find_if(mCachedBuffers.begin(), mCachedBuffers.end(), - [&handles](auto &buffer) { return (buffer->bufHandles == handles); }); - if (it != mCachedBuffers.end()) { - fbId = (*it)->fbId; - mStagingBuffers.splice(mStagingBuffers.end(), mCachedBuffers, it); - return NO_ERROR; - } - } - ret = addFB2WithModifiers(bufWidth, bufHeight, drmFormat, handles, pitches, offsets, modifiers, &fbId, modifiers[0] ? DRM_MODE_FB_MODIFIERS : 0); + for (uint32_t bufferIndex = 0; bufferIndex < bufferNum; bufferIndex++) { + freeBufHandle(handles[bufferIndex]); + } + if (ret) { ALOGE("%s:: Failed to add FB, fb_id(%d), ret(%d), f_w: %d, f_h: %d, dst.w: %d, dst.h: %d, " "format: %d %4.4s, buf_handles[%d, %d, %d, %d], " @@ -256,48 +265,49 @@ int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint return ret; } - if (caching) { + if (config.layer || config.buffer_id) { Mutex::Autolock lock(mMutex); - mStagingBuffers.emplace_back(new Framebuffer(mDrmFd, handles, bufferNum, fbId)); + if (mCachedLayerBuffers[config.layer].size() > MAX_CACHED_BUFFERS) { + ALOGW("Framebuffer: cached buffers size %zu exceeds limitation while adding fbId %d", + mCachedLayerBuffers[config.layer].size(), fbId); + } + mCachedLayerBuffers[config.layer].emplace_back( + new Framebuffer(mDrmFd, config.buffer_id, config.fd_idma[0], fbId)); + } else { + ALOGW("Framebuffer: possible leakage fbId %d was created", fbId); } return 0; } -void FramebufferManager::flip(bool isActiveCommit) -{ - { - Mutex::Autolock lock(mMutex); - nsecs_t lastCommitTime = systemTime(SYSTEM_TIME_MONOTONIC); - if (isActiveCommit) { - mLastActiveCommitTime = lastCommitTime; - for (auto &it : mStagingBuffers) { - it->lastLookupTime = lastCommitTime; - } - } - mCachedBuffers.splice(mCachedBuffers.end(), mStagingBuffers); - } - mCondition.signal(); +void FramebufferManager::flip() { + mFlipDone.signal(); } void FramebufferManager::releaseAll() { Mutex::Autolock lock(mMutex); - mStagingBuffers.clear(); - mCachedBuffers.clear(); + mCachedLayerBuffers.clear(); } -void FramebufferManager::Framebuffer::freeBufHandle(uint32_t handle) -{ +void FramebufferManager::freeBufHandle(uint32_t handle) { + if (handle == 0) { + return; + } + struct drm_gem_close gem_close { .handle = handle }; - int ret = drmIoctl(drmFd, DRM_IOCTL_GEM_CLOSE, &gem_close); + int ret = drmIoctl(mDrmFd, DRM_IOCTL_GEM_CLOSE, &gem_close); if (ret) { - ALOGE("Failed to close gem handle with error %d\n", ret); + ALOGE("Failed to close gem handle 0x%x with error %d\n", handle, ret); } } +void ExynosDisplayDrmInterface::destroyLayer(ExynosLayer *layer) { + mFBManager.cleanup(layer); +} + ExynosDisplayDrmInterface::ExynosDisplayDrmInterface(ExynosDisplay *exynosDisplay) { mType = INTERFACE_TYPE_DRM; @@ -1323,8 +1333,11 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() std::unordered_map<uint32_t, uint32_t> planeEnableInfo; android::String8 result; - funcReturnCallback retCallback( - [&]() { mFBManager.flip((ret == NO_ERROR) && !drmReq.getError()); }); + funcReturnCallback retCallback([&]() { + if ((ret == NO_ERROR) && !drmReq.getError()) { + mFBManager.flip(); + } + }); if (mExynosDisplay->mDpuData.enable_readback) { if ((ret = setupWritebackCommit(drmReq)) < 0) { @@ -1848,7 +1861,7 @@ int32_t ExynosDisplayDrmInterface::setupWritebackCommit(DrmModeAtomicReq &drmReq writeback_config.fd_idma[0] = gmeta.fd; writeback_config.fd_idma[1] = gmeta.fd1; writeback_config.fd_idma[2] = gmeta.fd2; - if ((ret = mFBManager.getBuffer(writeback_config, writeback_fb_id, false)) < 0) { + if ((ret = mFBManager.getBuffer(writeback_config, writeback_fb_id)) < 0) { ALOGE("%s: getBuffer() fail ret(%d)", __func__, ret); return ret; } diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h index 04efd54..cf337f0 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h +++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h @@ -44,7 +44,6 @@ using namespace android; using DrmPropertyMap = std::unordered_map<uint32_t, uint64_t>; class ExynosDevice; -constexpr uint32_t MAX_CACHED_BUFFERS = 32; // TODO: find a good value for this using BufHandles = std::array<uint32_t, HWC_DRM_BO_MAX_PLANES>; class FramebufferManager { @@ -54,16 +53,18 @@ class FramebufferManager { void init(int drmFd); // get buffer for provided config, if a buffer with same config is already cached it will be - // reused otherwise one will be allocated. returns fbId that can be used to attach to plane, any - // buffers allocated/reused with this call will be staged, flip() call is expected after this - // when frame is committed - int32_t getBuffer(const exynos_win_config_data &config, uint32_t &fbId, bool caching = true); + // reused otherwise one will be allocated. returns fbId that can be used to attach to the + // plane, any buffers allocated/reused with this call will be bound to the corresponding + // layer. Those fbIds will be cleaned up once the layer was destroyed. + int32_t getBuffer(const exynos_win_config_data &config, uint32_t &fbId); - // this should be called after frame update - // this will move all staged buffers to front of the cached buffers queue - // This will also schedule a cleanup of cached buffers if cached buffer list goes - // beyond MAX_CACHED_BUFFERS - void flip(bool isActiveCommit); + void cleanup(const ExynosLayer *layer); + + // The flip function is to help clean up the cached fbIds of destroyed + // layers after the previous fdIds were update successfully on the + // screen. + // This should be called after the frame update. + void flip(); // release all currently tracked buffers, this can be called for example when display is turned // off @@ -73,20 +74,13 @@ class FramebufferManager { uint32_t getBufHandleFromFd(int fd); // this struct should contain elements that can be used to identify framebuffer more easily struct Framebuffer { - Framebuffer(int fd, BufHandles handles, uint32_t bufNum, uint32_t fb) - : bufHandles(handles), bufferNum(bufNum), fbId(fb), drmFd(fd){}; - ~Framebuffer() { - for (uint32_t i = 0; i < bufferNum; i++) { - if (bufHandles[i]) freeBufHandle(bufHandles[i]); - } - drmModeRmFB(drmFd, fbId); - }; - void freeBufHandle(uint32_t handle); - BufHandles bufHandles; - uint32_t bufferNum; - uint32_t fbId; + explicit Framebuffer(int fd, uint64_t bufId, int bufFd, uint32_t fb) + : drmFd(fd), buffer_id(bufId), fd(bufFd), fbId(fb){}; + ~Framebuffer() { drmModeRmFB(drmFd, fbId); }; int drmFd; - nsecs_t lastLookupTime = 0; + uint64_t buffer_id; + int fd; + uint32_t fbId; }; using FBList = std::list<std::unique_ptr<Framebuffer>>; @@ -95,25 +89,25 @@ class FramebufferManager { const uint32_t offsets[4], const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags); + void freeBufHandle(uint32_t handle); void removeFBsThreadRoutine(); - // releases framebuffers at the back of the cached buffer queue that go beyond - // MAX_CACHED_BUFFERS - void cleanup(FBList &cleanupBuffers); + // mCachedLayerBuffers map keep the relationship between Layer and + // FBList. The map entry will be deleted once the layer is destroyed. + std::map<const ExynosLayer *, FBList> mCachedLayerBuffers; - // buffers that are going to be committed in the next atomic frame update - FBList mStagingBuffers; - // unused buffers that have been used recently, front of the queue has the most recently used - // ones - FBList mCachedBuffers; + // mCleanBuffers list keeps fbIds of destroyed layers. Those fbIds will + // be destroyed in mRmFBThread thread. + FBList mCleanBuffers; int mDrmFd = -1; - nsecs_t mLastActiveCommitTime = 0; std::thread mRmFBThread; bool mRmFBThreadRunning = false; - Condition mCondition; + Condition mFlipDone; Mutex mMutex; + + static constexpr uint32_t MAX_CACHED_BUFFERS = 32; // TODO: find a good value for this }; class ExynosDisplayDrmInterface : @@ -252,6 +246,7 @@ class ExynosDisplayDrmInterface : { return NO_ERROR;}; virtual int32_t updateBrightness(bool syncFrame); virtual float getSdrDimRatio(); + virtual void destroyLayer(ExynosLayer *layer) override; bool isHbmOn() { return mBrightnessCtrl.HbmOn.get(); } uint32_t getDbv() { return mBrightnessLevel.get(); } diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h b/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h index 3b3815c..9033fb2 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h +++ b/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h @@ -75,6 +75,7 @@ class ExynosDisplayInterface { bool isPrimary(); /* For HWC 2.4 APIs */ virtual int32_t getVsyncAppliedTime(hwc2_config_t __unused config, int64_t* __unused actualChangeTime) {return NO_ERROR;} + virtual void destroyLayer(ExynosLayer* __unused layer){}; public: uint32_t mType = INTERFACE_TYPE_NONE; |