summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libhwc2.1/libdevice/ExynosDisplay.cpp5
-rw-r--r--libhwc2.1/libdevice/ExynosDisplay.h2
-rw-r--r--libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp117
-rw-r--r--libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h61
-rw-r--r--libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h1
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;