From dd8b6a2cc92b58d12845b42b1f4742482647d859 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 6 Sep 2021 01:12:09 +0300 Subject: cam: drm: Avoid importing the same dmabuf multiple times When creating a DRM frame buffer, the dmabufs for the planes are imported as GEM objects. For multi-planar formats, all planes may use the same dmabuf, which results in multiple imports. This doesn't cause any issue at import time, as DRM detects this situation and returns the same GEM object. However, when destroying the frame buffer, the same GEM object ends up being closed multiple times, which generates an error. Fix this by avoiding multiple imports of the same dmabuf for the same frame buffer. While the issue may theoretically occur with identical dmabufs for different frame buffers, this is quite unlikely and is thus not addressed. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham --- src/cam/drm.cpp | 29 +++++++++++++++++------------ src/cam/drm.h | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) (limited to 'src/cam') diff --git a/src/cam/drm.cpp b/src/cam/drm.cpp index d5a75d03..f2530091 100644 --- a/src/cam/drm.cpp +++ b/src/cam/drm.cpp @@ -283,9 +283,9 @@ FrameBuffer::FrameBuffer(Device *dev) FrameBuffer::~FrameBuffer() { - for (FrameBuffer::Plane &plane : planes_) { + for (const auto &plane : planes_) { struct drm_gem_close gem_close = { - .handle = plane.handle, + .handle = plane.second.handle, .pad = 0, }; int ret; @@ -605,23 +605,28 @@ std::unique_ptr Device::createFrameBuffer( int ret; const std::vector &planes = buffer.planes(); - fb->planes_.reserve(planes.size()); unsigned int i = 0; for (const libcamera::FrameBuffer::Plane &plane : planes) { + int fd = plane.fd.fd(); uint32_t handle; - ret = drmPrimeFDToHandle(fd_, plane.fd.fd(), &handle); - if (ret < 0) { - ret = -errno; - std::cerr - << "Unable to import framebuffer dmabuf: " - << strerror(-ret) << std::endl; - return nullptr; + auto iter = fb->planes_.find(fd); + if (iter == fb->planes_.end()) { + ret = drmPrimeFDToHandle(fd_, plane.fd.fd(), &handle); + if (ret < 0) { + ret = -errno; + std::cerr + << "Unable to import framebuffer dmabuf: " + << strerror(-ret) << std::endl; + return nullptr; + } + + fb->planes_[fd] = { handle }; + } else { + handle = iter->second.handle; } - fb->planes_.push_back({ handle }); - handles[i] = handle; offsets[i] = plane.offset; ++i; diff --git a/src/cam/drm.h b/src/cam/drm.h index 00f7e798..0b88f9a3 100644 --- a/src/cam/drm.h +++ b/src/cam/drm.h @@ -242,7 +242,7 @@ private: FrameBuffer(Device *dev); - std::vector planes_; + std::map planes_; }; class AtomicRequest -- cgit v1.2.1