From patchwork Thu Jul 4 22:53:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1622 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7757460C2C for ; Fri, 5 Jul 2019 00:52:27 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 0EEFC1C0002; Thu, 4 Jul 2019 22:52:26 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:26 +0200 Message-Id: <20190704225334.26170-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/9] libcamera: stream: Provide accessors to buffers X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:27 -0000 All interactions with the Stream's buffers currently go through the BufferPool. In order to shorten accessing the buffers array, and restrict access to the Stream's internal buffer pool, provide operations to access the buffers, create and destroy them. It is still possible to access the pool for pipeline handlers to populate it by exporting buffers from a video device to the pool. Signed-off-by: Jacopo Mondi --- include/libcamera/stream.h | 12 ++++++++++ src/cam/capture.cpp | 4 ++-- src/libcamera/camera.cpp | 6 ++--- src/libcamera/pipeline/ipu3/ipu3.cpp | 4 ++-- src/libcamera/stream.cpp | 35 ++++++++++++++++++++++++++++ src/qcam/main_window.cpp | 4 +--- test/camera/capture.cpp | 3 +-- test/camera/statemachine.cpp | 3 +-- 8 files changed, 57 insertions(+), 14 deletions(-) diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index 5b4fea324ce4..fa7d6ba4987c 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -66,12 +66,24 @@ class Stream { public: Stream(); + /* + * FIXME: + * If I could find a way to export buffers in pipeline handlers + * without accessing the pool with + * video_->exportBuffers(&stream->bufferPool()); + * we could remove access to the internal pool completely. + */ BufferPool &bufferPool() { return bufferPool_; } + std::vector &buffers() { return bufferPool_.buffers(); } + unsigned int bufferCount() const { return bufferPool_.count(); } const StreamConfiguration &configuration() const { return configuration_; } protected: friend class Camera; + void createBuffers(unsigned int count); + void destroyBuffers(); + BufferPool bufferPool_; StreamConfiguration configuration_; }; diff --git a/src/cam/capture.cpp b/src/cam/capture.cpp index 6b842d73390d..1bcc9c7e9cf4 100644 --- a/src/cam/capture.cpp +++ b/src/cam/capture.cpp @@ -76,7 +76,7 @@ int Capture::capture(EventLoop *loop) unsigned int nbuffers = UINT_MAX; for (StreamConfiguration &cfg : *config_) { Stream *stream = cfg.stream(); - nbuffers = std::min(nbuffers, stream->bufferPool().count()); + nbuffers = std::min(nbuffers, stream->bufferCount()); } /* @@ -95,7 +95,7 @@ int Capture::capture(EventLoop *loop) std::map map; for (StreamConfiguration &cfg : *config_) { Stream *stream = cfg.stream(); - map[stream] = &stream->bufferPool().buffers()[i]; + map[stream] = &stream->buffers()[i]; } ret = request->setBuffers(map); diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 592dfd39eacc..088a39623e36 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -683,7 +683,7 @@ int Camera::configure(CameraConfiguration *config) * Allocate buffer objects in the pool. * Memory will be allocated and assigned later. */ - stream->bufferPool().createBuffers(cfg.bufferCount); + stream->createBuffers(cfg.bufferCount); } state_ = CameraConfigured; @@ -740,14 +740,14 @@ int Camera::freeBuffers() return -EACCES; for (Stream *stream : activeStreams_) { - if (!stream->bufferPool().count()) + if (!stream->bufferCount()) continue; /* * All mappings must be destroyed before buffers can be freed * by the V4L2 device that has allocated them. */ - stream->bufferPool().destroyBuffers(); + stream->destroyBuffers(); } state_ = CameraConfigured; diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index e4efb9722f76..2de0892138a8 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -634,7 +634,7 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, * of buffers as the active ones. */ if (!outStream->active_) { - bufferCount = vfStream->bufferPool().count(); + bufferCount = vfStream->bufferCount(); outStream->device_->pool->createBuffers(bufferCount); ret = imgu->exportBuffers(outStream->device_, outStream->device_->pool); @@ -643,7 +643,7 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, } if (!vfStream->active_) { - bufferCount = outStream->bufferPool().count(); + bufferCount = outStream->bufferCount(); vfStream->device_->pool->createBuffers(bufferCount); ret = imgu->exportBuffers(vfStream->device_, vfStream->device_->pool); diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index d8e87c62281c..35197be09c26 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -418,12 +418,47 @@ Stream::Stream() * \return A reference to the buffer pool */ +/** + * \fn Stream::buffers() + * \brief Retrieve the stream's buffers + * \return The list of stream's buffers + */ + +/** + * \fn Stream::bufferCount() + * \brief Retrieve the number of buffers in the stream + * \return The number of stream buffers + */ + /** * \fn Stream::configuration() * \brief Retrieve the active configuration of the stream * \return The active configuration of the stream */ +/** + * \brief Create buffers for the stream + * \param count The number of buffers to create + * + * Create \a count empty buffers in the Stream's buffer pool. + */ +void Stream::createBuffers(unsigned int count) +{ + destroyBuffers(); + if (count == 0) + return; + + bufferPool_.createBuffers(count); +} + +/** + * \brief Destroy buffers in the stream + */ +void Stream::destroyBuffers() +{ + bufferPool_.destroyBuffers(); +} + /** * \var Stream::bufferPool_ * \brief The pool of buffers associated with the stream diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 16b123132dd9..a0703b322c16 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -122,10 +122,8 @@ int MainWindow::startCapture() return ret; } - BufferPool &pool = stream->bufferPool(); std::vector requests; - - for (Buffer &buffer : pool.buffers()) { + for (Buffer &buffer : stream->buffers()) { Request *request = camera_->createRequest(); if (!request) { std::cerr << "Can't create request" << std::endl; diff --git a/test/camera/capture.cpp b/test/camera/capture.cpp index 7ce247cc482d..a0385ec2c74d 100644 --- a/test/camera/capture.cpp +++ b/test/camera/capture.cpp @@ -76,9 +76,8 @@ protected: } Stream *stream = cfg.stream(); - BufferPool &pool = stream->bufferPool(); std::vector requests; - for (Buffer &buffer : pool.buffers()) { + for (Buffer &buffer : stream->buffers()) { Request *request = camera_->createRequest(); if (!request) { cout << "Failed to create request" << endl; diff --git a/test/camera/statemachine.cpp b/test/camera/statemachine.cpp index 84d2a6fab5f0..c23455b5bb21 100644 --- a/test/camera/statemachine.cpp +++ b/test/camera/statemachine.cpp @@ -211,8 +211,7 @@ protected: return TestFail; Stream *stream = *camera_->streams().begin(); - BufferPool &pool = stream->bufferPool(); - Buffer &buffer = pool.buffers().front(); + Buffer &buffer = stream->buffers().front(); std::map map = { { stream, &buffer } }; if (request->setBuffers(map)) return TestFail; From patchwork Thu Jul 4 22:53:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1623 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 10ECA60C2C for ; Fri, 5 Jul 2019 00:52:28 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 9ED701C0002; Thu, 4 Jul 2019 22:52:27 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:27 +0200 Message-Id: <20190704225334.26170-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/9] libcamera: stream: Add Stream memory type X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:28 -0000 Define the memory type a Stream uses and allow application to set it through the associated StreamConfiguration. A Stream can use either internal or external memory allocation methods, depending on where the data produced by the stream is actually saved. Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- include/libcamera/stream.h | 8 ++++++++ src/libcamera/camera.cpp | 1 + src/libcamera/stream.cpp | 30 ++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index fa7d6ba4987c..796f1aff2602 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -34,6 +34,11 @@ private: std::map> formats_; }; +enum MemoryType { + InternalMemory, + ExternalMemory, +}; + struct StreamConfiguration { StreamConfiguration(); StreamConfiguration(const StreamFormats &formats); @@ -41,6 +46,7 @@ struct StreamConfiguration { unsigned int pixelFormat; Size size; + MemoryType memoryType; unsigned int bufferCount; Stream *stream() const { return stream_; } @@ -77,6 +83,7 @@ public: std::vector &buffers() { return bufferPool_.buffers(); } unsigned int bufferCount() const { return bufferPool_.count(); } const StreamConfiguration &configuration() const { return configuration_; } + MemoryType memoryType() const { return memoryType_; } protected: friend class Camera; @@ -86,6 +93,7 @@ protected: BufferPool bufferPool_; StreamConfiguration configuration_; + MemoryType memoryType_; }; } /* namespace libcamera */ diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 088a39623e36..5f756d41744a 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -683,6 +683,7 @@ int Camera::configure(CameraConfiguration *config) * Allocate buffer objects in the pool. * Memory will be allocated and assigned later. */ + stream->memoryType_ = cfg.memoryType; stream->createBuffers(cfg.bufferCount); } diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index 35197be09c26..97e0f429c9fb 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -263,6 +263,16 @@ SizeRange StreamFormats::range(unsigned int pixelformat) const return range; } +/** + * \enum MemoryType + * \brief Define the memory type used by a Stream + * \var MemoryType::InternalMemory + * The Stream uses memory allocated internally to the library and export that + * to applications. + * \var MemoryType::ExternalMemory + * The Stream uses buffers whose memory is allocated outside from the library. + */ + /** * \struct StreamConfiguration * \brief Configuration parameters for a stream @@ -276,7 +286,7 @@ SizeRange StreamFormats::range(unsigned int pixelformat) const * handlers provied StreamFormats. */ StreamConfiguration::StreamConfiguration() - : stream_(nullptr) + : memoryType(InternalMemory), stream_(nullptr) { } @@ -284,7 +294,7 @@ StreamConfiguration::StreamConfiguration() * \brief Construct a configuration with stream formats */ StreamConfiguration::StreamConfiguration(const StreamFormats &formats) - : stream_(nullptr), formats_(formats) + : memoryType(InternalMemory), stream_(nullptr), formats_(formats) { } @@ -301,6 +311,11 @@ StreamConfiguration::StreamConfiguration(const StreamFormats &formats) * format described in V4L2 using the V4L2_PIX_FMT_* definitions. */ +/** + * \var StreamConfiguration::memoryType + * \brief The memory type the stream shall use + */ + /** * \var StreamConfiguration::bufferCount * \brief Requested number of buffers to allocate for the stream @@ -436,6 +451,12 @@ Stream::Stream() * \return The active configuration of the stream */ +/** + * \fn Stream::memoryType() + * \brief Retrieve the stream memory type + * \return The memory type used by the stream + */ + /** * \brief Create buffers for the stream * \param count The number of buffers to create @@ -476,4 +497,9 @@ void Stream::destroyBuffers() * next call to Camera::configure() regardless of if it includes the stream. */ +/** + * \var Stream::memoryType_ + * \brief The stream memory type + */ + } /* namespace libcamera */ From patchwork Thu Jul 4 22:53:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1624 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A09E060C2C for ; Fri, 5 Jul 2019 00:52:28 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 36F2C1C0002; Thu, 4 Jul 2019 22:52:28 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:28 +0200 Message-Id: <20190704225334.26170-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/9] libcamera: pipeline: Support external buffers X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:29 -0000 Add support for use external buffers to libcamera pipeline handlers. Use the memory type flag in pipeline handlers (todo: change all pipeline handlers) during buffer setup operations, to decide if the Stream's internal memory has to be exported to applications, or the Stream should prepare to use buffers whose memory is allocated elsewhere. To support the last use case, a translation mechanism between the external buffers provided by applications and internal ones used by pipeline handlers to feed the video device will be implemented on top of this change. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 31 +++++++++++++++++++++++- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 9 ++++++- src/libcamera/pipeline/uvcvideo.cpp | 8 +++++- src/libcamera/pipeline/vimc.cpp | 8 +++++- 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 2de0892138a8..6f14da1f8c70 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -71,6 +71,7 @@ public: int importBuffers(BufferPool *pool); int exportBuffers(ImgUOutput *output, BufferPool *pool); + int reserveDmabufBuffers(ImgUOutput *output, BufferPool *pool); void freeBuffers(); int start(); @@ -624,7 +625,11 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, IPU3Stream *stream = static_cast(s); ImgUDevice::ImgUOutput *dev = stream->device_; - ret = imgu->exportBuffers(dev, &stream->bufferPool()); + if (stream->memoryType() == ExternalMemory) + ret = imgu->reserveDmabufBuffers(dev, + &stream->bufferPool()); + else + ret = imgu->exportBuffers(dev, &stream->bufferPool()); if (ret) goto error; } @@ -1153,6 +1158,30 @@ int ImgUDevice::exportBuffers(ImgUOutput *output, BufferPool *pool) return 0; } +/** + * \brief Reserve buffers in \a output from the provided \a pool + * \param[in] output The ImgU output device + * \param[in] pool The buffer pool used to reserve buffers in \a output + * + * Reserve a number of buffers equal to the number of buffers in \a pool + * in the \a output device to prepare for streaming operations using buffers + * whose memory has been reserved elsewhere identified with DMABUF file + * descriptors. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::reserveDmabufBuffers(ImgUOutput *output, BufferPool *pool) +{ + int ret = output->dev->importBuffers(pool); + if (ret) { + LOG(IPU3, Error) << "Failed to import buffer in " + << output->name << " ImgU device"; + return ret; + } + + return 0; +} + /** * \brief Release buffers for all the ImgU video devices */ diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 4a5898d25f91..dbb61a21354d 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -319,7 +319,14 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera, const std::set &streams) { Stream *stream = *streams.begin(); - return video_->exportBuffers(&stream->bufferPool()); + int ret; + + if (stream->memoryType() == InternalMemory) + ret = video_->exportBuffers(&stream->bufferPool()); + else + ret = video_->importBuffers(&stream->bufferPool()); + + return ret; } int PipelineHandlerRkISP1::freeBuffers(Camera *camera, diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 72313cfd246f..5b3c79dda6dd 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -197,10 +197,16 @@ int PipelineHandlerUVC::allocateBuffers(Camera *camera, UVCCameraData *data = cameraData(camera); Stream *stream = *streams.begin(); const StreamConfiguration &cfg = stream->configuration(); + int ret; LOG(UVC, Debug) << "Requesting " << cfg.bufferCount << " buffers"; - return data->video_->exportBuffers(&stream->bufferPool()); + if (stream->memoryType() == InternalMemory) + ret = data->video_->exportBuffers(&stream->bufferPool()); + else + ret = data->video_->importBuffers(&stream->bufferPool()); + + return ret; } int PipelineHandlerUVC::freeBuffers(Camera *camera, diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index f8a58be060bb..c67bdb0ecbff 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -199,10 +199,16 @@ int PipelineHandlerVimc::allocateBuffers(Camera *camera, VimcCameraData *data = cameraData(camera); Stream *stream = *streams.begin(); const StreamConfiguration &cfg = stream->configuration(); + int ret; LOG(VIMC, Debug) << "Requesting " << cfg.bufferCount << " buffers"; - return data->video_->exportBuffers(&stream->bufferPool()); + if (stream->memoryType() == InternalMemory) + ret = data->video_->exportBuffers(&stream->bufferPool()); + else + ret = data->video_->importBuffers(&stream->bufferPool()); + + return ret; } int PipelineHandlerVimc::freeBuffers(Camera *camera, From patchwork Thu Jul 4 22:53:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1625 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3933A60C2C for ; Fri, 5 Jul 2019 00:52:29 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id C3FA21C0007; Thu, 4 Jul 2019 22:52:28 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:29 +0200 Message-Id: <20190704225334.26170-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 4/9] libcamera: Rename PipelineHandler::allocateBuffers X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:29 -0000 Now that the pipeline handlers can inspect the Stream's memory type flag the allocateBuffers() operation name does not match the actual operation purpose, which is to setup buffers to export memory to application or either prepare to use externally allocated buffers. Todo: rename the camera operation as well? Signed-off-by: Jacopo Mondi --- src/libcamera/camera.cpp | 2 +- src/libcamera/include/pipeline_handler.h | 4 ++-- src/libcamera/pipeline/ipu3/ipu3.cpp | 8 ++++---- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 6 +++--- src/libcamera/pipeline/uvcvideo.cpp | 8 ++++---- src/libcamera/pipeline/vimc.cpp | 8 ++++---- src/libcamera/pipeline_handler.cpp | 6 ++++-- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 5f756d41744a..f3f01d040ecf 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -716,7 +716,7 @@ int Camera::allocateBuffers() return -EINVAL; } - int ret = pipe_->allocateBuffers(this, activeStreams_); + int ret = pipe_->setupBuffers(this, activeStreams_); if (ret) { LOG(Camera, Error) << "Failed to allocate buffers"; return ret; diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h index f836d5d1a600..c40d108eb13c 100644 --- a/src/libcamera/include/pipeline_handler.h +++ b/src/libcamera/include/pipeline_handler.h @@ -68,8 +68,8 @@ public: const StreamRoles &roles) = 0; virtual int configure(Camera *camera, CameraConfiguration *config) = 0; - virtual int allocateBuffers(Camera *camera, - const std::set &streams) = 0; + virtual int setupBuffers(Camera *camera, + const std::set &streams) = 0; virtual int freeBuffers(Camera *camera, const std::set &streams) = 0; diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 6f14da1f8c70..28dcefe3d19f 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -208,8 +208,8 @@ public: const StreamRoles &roles) override; int configure(Camera *camera, CameraConfiguration *config) override; - int allocateBuffers(Camera *camera, - const std::set &streams) override; + int setupBuffers(Camera *camera, + const std::set &streams) override; int freeBuffers(Camera *camera, const std::set &streams) override; @@ -589,8 +589,8 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) * In order to be able to start the 'viewfinder' and 'stat' nodes, we need * memory to be reserved. */ -int PipelineHandlerIPU3::allocateBuffers(Camera *camera, - const std::set &streams) +int PipelineHandlerIPU3::setupBuffers(Camera *camera, + const std::set &streams) { IPU3CameraData *data = cameraData(camera); IPU3Stream *outStream = &data->outStream_; diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index dbb61a21354d..836de1f61630 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -80,7 +80,7 @@ public: const StreamRoles &roles) override; int configure(Camera *camera, CameraConfiguration *config) override; - int allocateBuffers(Camera *camera, + int setupBuffers(Camera *camera, const std::set &streams) override; int freeBuffers(Camera *camera, const std::set &streams) override; @@ -315,8 +315,8 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c) return 0; } -int PipelineHandlerRkISP1::allocateBuffers(Camera *camera, - const std::set &streams) +int PipelineHandlerRkISP1::setupBuffers(Camera *camera, + const std::set &streams) { Stream *stream = *streams.begin(); int ret; diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 5b3c79dda6dd..bba4e7f8d2a0 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -63,8 +63,8 @@ public: const StreamRoles &roles) override; int configure(Camera *camera, CameraConfiguration *config) override; - int allocateBuffers(Camera *camera, - const std::set &streams) override; + int setupBuffers(Camera *camera, + const std::set &streams) override; int freeBuffers(Camera *camera, const std::set &streams) override; @@ -191,8 +191,8 @@ int PipelineHandlerUVC::configure(Camera *camera, CameraConfiguration *config) return 0; } -int PipelineHandlerUVC::allocateBuffers(Camera *camera, - const std::set &streams) +int PipelineHandlerUVC::setupBuffers(Camera *camera, + const std::set &streams) { UVCCameraData *data = cameraData(camera); Stream *stream = *streams.begin(); diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index c67bdb0ecbff..3e08768b670f 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -70,8 +70,8 @@ public: const StreamRoles &roles) override; int configure(Camera *camera, CameraConfiguration *config) override; - int allocateBuffers(Camera *camera, - const std::set &streams) override; + int setupBuffers(Camera *camera, + const std::set &streams) override; int freeBuffers(Camera *camera, const std::set &streams) override; @@ -193,8 +193,8 @@ int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config) return 0; } -int PipelineHandlerVimc::allocateBuffers(Camera *camera, - const std::set &streams) +int PipelineHandlerVimc::setupBuffers(Camera *camera, + const std::set &streams) { VimcCameraData *data = cameraData(camera); Stream *stream = *streams.begin(); diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 0283e4e5ad51..67b215483847 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -280,11 +280,13 @@ const ControlInfoMap &PipelineHandler::controls(Camera *camera) */ /** - * \fn PipelineHandler::allocateBuffers() - * \brief Allocate buffers for a stream + * \fn PipelineHandler::setupBuffers() + * \brief Setup buffer for a stream * \param[in] camera The camera the \a stream belongs to * \param[in] streams The set of streams to allocate buffers for * + * \todo Change this to describe both allocation and importing + * * This method allocates buffers internally in the pipeline handler for each * stream in the \a streams buffer set, and associates them with the stream's * buffer pool. From patchwork Thu Jul 4 22:53:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1626 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D511F60C2C for ; Fri, 5 Jul 2019 00:52:30 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 6174C1C0002; Thu, 4 Jul 2019 22:52:29 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:30 +0200 Message-Id: <20190704225334.26170-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 5/9] libcamera: request: Rename the Stream to Buffer map X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:31 -0000 As we're about to add support for mapping application buffers to streams' ones, rename the existing bufferMap_ to just buffers_, which also matches the associated accessor operation name. Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- include/libcamera/request.h | 4 ++-- src/libcamera/camera.cpp | 2 +- src/libcamera/request.cpp | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index a93468d7c8b7..70f6d7fa7eeb 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -34,7 +34,7 @@ public: Request &operator=(const Request &) = delete; ControlList &controls() { return controls_; } - const std::map &buffers() const { return bufferMap_; } + const std::map &buffers() const { return buffers_; } int setBuffers(const std::map &streamMap); Buffer *findBuffer(Stream *stream) const; @@ -53,7 +53,7 @@ private: Camera *camera_; ControlList controls_; - std::map bufferMap_; + std::map buffers_; std::unordered_set pending_; Status status_; diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index f3f01d040ecf..265755f1b9e3 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -895,7 +895,7 @@ int Camera::stop() */ void Camera::requestComplete(Request *request) { - std::map buffers(std::move(request->bufferMap_)); + std::map buffers(std::move(request->buffers_)); requestCompleted.emit(request, buffers); delete request; } diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index f0b5985814bd..9ff0abbf119c 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -86,20 +86,20 @@ Request::Request(Camera *camera) */ int Request::setBuffers(const std::map &streamMap) { - if (!bufferMap_.empty()) { + if (!buffers_.empty()) { LOG(Request, Error) << "Buffers already set"; return -EBUSY; } - bufferMap_ = streamMap; + buffers_ = streamMap; return 0; } /** - * \var Request::bufferMap_ + * \var Request::buffers_ * \brief Mapping of streams to buffers for this request * - * The bufferMap_ tracks the buffers associated with each stream. If a stream is + * The buffers_ tracks the buffers associated with each stream. If a stream is * not utilised in this request there will be no buffer for that stream in the * map. */ @@ -112,8 +112,8 @@ int Request::setBuffers(const std::map &streamMap) */ Buffer *Request::findBuffer(Stream *stream) const { - auto it = bufferMap_.find(stream); - if (it == bufferMap_.end()) + auto it = buffers_.find(stream); + if (it == buffers_.end()) return nullptr; return it->second; @@ -150,12 +150,12 @@ Buffer *Request::findBuffer(Stream *stream) const */ int Request::prepare() { - if (bufferMap_.empty()) { + if (buffers_.empty()) { LOG(Request, Error) << "Invalid request due to missing buffers"; return -EINVAL; } - for (auto const &pair : bufferMap_) { + for (auto const &pair : buffers_) { Buffer *buffer = pair.second; buffer->setRequest(this); pending_.insert(buffer); From patchwork Thu Jul 4 22:53:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1627 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6E3B560C2C for ; Fri, 5 Jul 2019 00:52:31 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 060D11C0008; Thu, 4 Jul 2019 22:52:30 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:31 +0200 Message-Id: <20190704225334.26170-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 6/9] libcamera: stream: Add operation to map buffers X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:31 -0000 Add and operation to map external buffers provided by applications in a Request to the Stream's internal buffers used by the pipeline handlers to interact with the video device. Signed-off-by: Jacopo Mondi --- include/libcamera/buffer.h | 1 + include/libcamera/stream.h | 6 ++ src/libcamera/stream.cpp | 116 +++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h index 260a62e9e77e..d5d3dc90a096 100644 --- a/include/libcamera/buffer.h +++ b/include/libcamera/buffer.h @@ -59,6 +59,7 @@ private: friend class BufferPool; friend class PipelineHandler; friend class Request; + friend class Stream; friend class V4L2VideoDevice; void cancel(); diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index 796f1aff2602..74415062cbdd 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -85,6 +85,8 @@ public: const StreamConfiguration &configuration() const { return configuration_; } MemoryType memoryType() const { return memoryType_; } + Buffer *mapBuffer(Buffer *applicationBuffer); + protected: friend class Camera; @@ -94,6 +96,10 @@ protected: BufferPool bufferPool_; StreamConfiguration configuration_; MemoryType memoryType_; + +private: + std::vector mappableBuffers_; + std::map bufferMap_; }; } /* namespace libcamera */ diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index 97e0f429c9fb..4585c0db77a4 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -13,6 +13,8 @@ #include #include +#include + #include "log.h" /** @@ -470,6 +472,26 @@ void Stream::createBuffers(unsigned int count) return; bufferPool_.createBuffers(count); + + /* Streams with internal memory usage do not need buffer mapping. */ + if (memoryType_ == InternalMemory) + return; + + /* + * Prepare for buffer mapping by queuing all buffers from the internal + * pool. Each external buffer presented by application will be mapped + * on an internal one. + */ + mappableBuffers_.clear(); + for (Buffer &buffer : bufferPool_.buffers()) { + /* + * Reserve all planes to support mapping multiplanar buffers. + * \todo I would use VIDEO_MAX_PLANES but it's a V4L2 thing. + */ + buffer.planes().resize(3); + + mappableBuffers_.push_back(&buffer); + } } /** @@ -480,6 +502,100 @@ void Stream::destroyBuffers() bufferPool_.destroyBuffers(); } +/** + * \brief Map an application provided buffer to a stream buffer + * \param applicationBuffer The application provided buffer + * + * If a Stream has been configured to use application provided buffers a + * mapping between the external buffers and the internal ones, which are + * actually used to interface with the video device, is required. + * + * The most commonly used mechanism to perform zero-copy memory sharing + * on Linux-based system is dmabuf, which allows user-space applications to + * share buffers by exchanging dmabuf generated file descriptors. This + * operations assumes that all application provided buffers have each of their + * used memory planes exported as dmabuf file descriptor, to copy them in + * the buffer to be then queued on the video device by pipeline handlers. + * + * Perform mapping by maintaining a cache in a map associating the dmabuf file + * descriptor of the application provided buffer to one of the stream's internal + * buffers to provide pipeline handlers the buffer to use to interact with video + * devices. + * + * Once the buffer completes, the mapping should be reverted to return to + * the application the buffer it first provided here. + * + * \return The stream buffer which maps to the application provided buffer + */ +Buffer *Stream::mapBuffer(Buffer *applicationBuffer) +{ + unsigned int key = applicationBuffer->planes()[0].dmabuf(); + + /* + * Buffer hit: the application buffer has already been mapped, return + * the assigned stream buffer + */ + auto mapped = bufferMap_.find(key); + if (mapped != bufferMap_.end()) { + Buffer *buffer = mapped->second; + + /* + * Keep the mappableBuffers_ vector warm: move the hit buffer to + * the vector end as on a buffer miss buffers are below evicted + * from the vector head. + */ + auto it = std::find(mappableBuffers_.begin(), + mappableBuffers_.end(), buffer); + + ASSERT(it != mappableBuffers_.end()); + std::rotate(it, it + 1, mappableBuffers_.end()); + + return buffer; + } + + /* + * Buffer miss: assign to the application buffer the stream buffer + * at mappableBuffers_ begin, then move it to the end. + */ + Buffer *buffer = *(mappableBuffers_.begin()); + std::rotate(mappableBuffers_.begin(), mappableBuffers_.begin() + 1, + mappableBuffers_.end()); + + + /* Remove the [key, buffer] entry buffer from the buffer map */ + auto deadBuf = std::find_if(bufferMap_.begin(), bufferMap_.end(), + [&](std::pair &map) { + return bufferMap_[map.first] == buffer; + }); + if (deadBuf != bufferMap_.end()) + bufferMap_.erase(deadBuf); + + /* + * Assign the buffer by copying the dmabuf file descriptors from the + * application provided buffer. + */ + for (unsigned int i = 0; i < applicationBuffer->planes().size(); ++i) { + int fd = applicationBuffer->planes()[i].dmabuf(); + + /* + * The ARC camera stack seems to report more planes that the + * ones it actually uses. + */ + if (fd < 0) + break; + + buffer->planes()[i].setDmabuf(fd, 0); + } + + /* Pipeline handlers use request_ at buffer completion time. */ + buffer->request_ = applicationBuffer->request(); + + /* And finally, store the mapping for later re-use and return it. */ + bufferMap_[key] = buffer; + + return buffer; +} + /** * \var Stream::bufferPool_ * \brief The pool of buffers associated with the stream From patchwork Thu Jul 4 22:53:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1628 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 11BD76156B for ; Fri, 5 Jul 2019 00:52:32 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 9C95F1C0008; Thu, 4 Jul 2019 22:52:31 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:32 +0200 Message-Id: <20190704225334.26170-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 7/9] libcamera: request: Support buffer mapping X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:32 -0000 Use the Stream class buffer mapping operation to save the association in the request at Request::findBuffer() time and reverse it with a new operation Request::unmapBuffer() used by the pipeline handler base class at buffer completion time, to return to the applications the Buffer they originally provided with the Request without involving the pipeline handlers in the process. Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- include/libcamera/request.h | 4 ++- src/libcamera/pipeline_handler.cpp | 6 ++-- src/libcamera/request.cpp | 45 ++++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 70f6d7fa7eeb..3353f037945e 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -36,7 +36,8 @@ public: ControlList &controls() { return controls_; } const std::map &buffers() const { return buffers_; } int setBuffers(const std::map &streamMap); - Buffer *findBuffer(Stream *stream) const; + Buffer *findBuffer(Stream *stream); + Buffer *unmapBuffer(Buffer *streamBuffer); Status status() const { return status_; } @@ -55,6 +56,7 @@ private: ControlList controls_; std::map buffers_; std::unordered_set pending_; + std::map bufferMap_; Status status_; }; diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 67b215483847..a47411ecf345 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -402,8 +402,10 @@ int PipelineHandler::queueRequest(Camera *camera, Request *request) bool PipelineHandler::completeBuffer(Camera *camera, Request *request, Buffer *buffer) { - camera->bufferCompleted.emit(request, buffer); - return request->completeBuffer(buffer); + Buffer *requestBuffer = request->unmapBuffer(buffer); + + camera->bufferCompleted.emit(request, requestBuffer); + return request->completeBuffer(requestBuffer); } /** diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 9ff0abbf119c..0e07d39f8941 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -105,17 +105,58 @@ int Request::setBuffers(const std::map &streamMap) */ /** - * \brief Return the buffer associated with a stream + * \brief Retrieve the stream buffer associated with a stream * \param[in] stream The stream the buffer is associated to + * + * Depending on the configured memory type, the buffers originally provided + * by the application might get mapped to streams internal buffers. + * + * \sa Stream::mapBuffer() + * * \return The buffer associated with the stream, or nullptr if the stream is * not part of this request */ -Buffer *Request::findBuffer(Stream *stream) const +Buffer *Request::findBuffer(Stream *stream) { auto it = buffers_.find(stream); if (it == buffers_.end()) return nullptr; + /* + * Streams with internal memory mode do not need to perform any mapping + * between the application provided buffers (part of the request) + * and the one actually used by the Stream. + * + * Streams using externally allocated buffers need to create a mapping + * between the application provided buffers and the one used by pipeline + * handlers. + */ + Buffer *requestBuffer = it->second; + Buffer *mappedBuffer = stream->memoryType() == InternalMemory ? + it->second : stream->mapBuffer(it->second); + bufferMap_[mappedBuffer] = requestBuffer; + + return mappedBuffer; +} + +/** + * \brief Retrieve the application buffer associated with \a streamBuffer + * \param streamBuffer The stream buffer returned from Request::findBuffer() + * + * This operation is used by the PipelineHandler base class to retrieve the + * buffer the application originally associated with the stream in the request. + * Depending on the configured memory type, application provided buffers might + * be mapped to streams internal buffers at Request::findBuffer() time. + * + * \sa Stream::mapBuffer() + * + * \return The application buffer provided to Request::findBuffer() + */ +Buffer *Request::unmapBuffer(Buffer *streamBuffer) +{ + auto it = bufferMap_.find(streamBuffer); + ASSERT(it != bufferMap_.end()); + return it->second; } From patchwork Thu Jul 4 22:53:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1629 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A01AE6156F for ; Fri, 5 Jul 2019 00:52:32 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 38EEC1C0008; Thu, 4 Jul 2019 22:52:32 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:33 +0200 Message-Id: <20190704225334.26170-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 8/9] libcamera: pipeline: ipu3: Use buffer mapping X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:32 -0000 In order to support the usage of application provided buffer, retrieve the buffer to use on video devices using the Request in order to allow the stream to perform buffer mapping, if requested. The IPU3 was the only pipeline handler to access the Request map directly instead of using Request::findBuffer(). Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- src/libcamera/pipeline/ipu3/ipu3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 28dcefe3d19f..49aa27ff20d4 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -725,7 +725,7 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) for (auto it : request->buffers()) { IPU3Stream *stream = static_cast(it.first); - Buffer *buffer = it.second; + Buffer *buffer = request->findBuffer(stream); int ret = stream->device_->dev->queueBuffer(buffer); if (ret < 0) From patchwork Thu Jul 4 22:53:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1630 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 380BD6156F for ; Fri, 5 Jul 2019 00:52:33 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id C49471C0008; Thu, 4 Jul 2019 22:52:32 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:34 +0200 Message-Id: <20190704225334.26170-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 9/9] [HACK] test: v4l2_videodevice: Add buffer import test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:33 -0000 Test buffer importing by streaming the camera to a video output device performing zero-copy memory sharing using dmabuf file descriptors. Not-yet-Signed-off-by: Jacopo Mondi --- Not suitable for merge yes. More a test utility for development at the moment. To be morhped into a camera test from a video device one. --- test/v4l2_videodevice/buffer_import.cpp | 234 ++++++++++++++++++++++++ test/v4l2_videodevice/meson.build | 1 + 2 files changed, 235 insertions(+) create mode 100644 test/v4l2_videodevice/buffer_import.cpp diff --git a/test/v4l2_videodevice/buffer_import.cpp b/test/v4l2_videodevice/buffer_import.cpp new file mode 100644 index 000000000000..0a294b055af5 --- /dev/null +++ b/test/v4l2_videodevice/buffer_import.cpp @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * libcamera V4L2 API tests + * + * Test importing buffers exported from an output device into a camera + */ + +#include + +#include +#include +#include +#include +#include + +#include "v4l2_videodevice_test.h" + +using namespace libcamera; +using namespace std; + +class BufferImportTest : public V4L2VideoDeviceTest +{ +public: + BufferImportTest() + : V4L2VideoDeviceTest("vivid", "vivid-000-vid-out") + { + } + +protected: + void cameraBufferComplete(Request *request, Buffer *buffer) + { + if (buffer->status() != Buffer::BufferSuccess) + return; + + capture_->queueBuffer(buffer); + } + + void requestComplete(Request *request, const std::map &buffers) + { + if (request->status() != Request::RequestComplete) + return; + + /* Reuse the buffers for a new request. */ + request = camera_->createRequest(); + request->setBuffers(buffers); + camera_->queueRequest(request); + } + + int init() + { + constexpr unsigned int bufferCount = 4; + + /* Get a camera where to capture frames from. */ + cm_ = CameraManager::instance(); + + if (cm_->start()) { + cout << "Failed to start camera manager" << endl; + return TestFail; + } + + camera_ = cm_->get("Integrated Camera: Integrated C"); + if (!camera_) { + cout << "Can not find VIMC camera" << endl; + return TestSkip; + } + + if (camera_->acquire()) { + cout << "Failed to acquire the camera" << endl; + return TestFail; + } + + /* + * Initialize the output device and export buffers in a pool. + * The 'output' device is actually called capture_ by the base + * class. + */ + int ret = V4L2VideoDeviceTest::init(); + if (ret) { + cerr << "Failed to initialize output device" << endl; + return ret; + } + + /* + * Set a known format on the output devices, then apply it + * to the camera. + */ + V4L2DeviceFormat format = {}; + if (capture_->getFormat(&format)) { + cleanup(); + return TestFail; + } + + format.size.width = 640; + format.size.height = 480; + format.fourcc = V4L2_PIX_FMT_YUYV; + format.planesCount = 1; + format.planes[0].size = 640 * 480 * 2; + format.planes[0].bpl = 640 * 2; + if (capture_->setFormat(&format)) { + cleanup(); + return TestFail; + } + + cout << "Output format: " << format.toString(); + + config_ = camera_->generateConfiguration({ StreamRole::VideoRecording }); + if (!config_ || config_->size() != 1) { + cout << "Failed to generate default configuration" << endl; + cleanup(); + return TestFail; + } + + /* + * Configure the Stream to work with externally allocated + * buffers by setting the memoryType to ExternalMemory. + */ + StreamConfiguration &cfg = config_->at(0); + cfg.size = format.size; + cfg.pixelFormat = format.fourcc; + cfg.memoryType = ExternalMemory; + + if (camera_->configure(config_.get())) { + cout << "Failed to set modified configuration" << endl; + cleanup(); + return TestFail; + } + cout << "Capture format: " << format.toString(); + + /* + * Export the output buffers to a pool and then import + * them before setting up buffers in the Camera. + */ + pool_.createBuffers(bufferCount); + ret = capture_->exportBuffers(&pool_); + if (ret) { + std::cout << "Failed to export buffers" << std::endl; + cleanup(); + return TestFail; + } + + if (camera_->allocateBuffers()) { + cout << "Failed to allocate buffers" << endl; + return TestFail; + } + + return TestPass; + } + + int run() + { + std::vector requests; + StreamConfiguration &cfg = config_->at(0); + Stream *stream = cfg.stream(); + /* Create one request for each output video buffer. */ + for (Buffer &buffer : pool_.buffers()) { + Request *request = camera_->createRequest(); + if (!request) { + cout << "Failed to create request" << endl; + return TestFail; + } + + std::map map = { { stream, &buffer } }; + if (request->setBuffers(map)) { + cout << "Failed to associating buffer with request" << endl; + return TestFail; + } + + requests.push_back(request); + } + + /* Connect the buffer ready signals of camera and output */ + camera_->bufferCompleted.connect(this, + &BufferImportTest::cameraBufferComplete); + + /* Connect the request ready signal to re-queue requests. */ + camera_->requestCompleted.connect(this, + &BufferImportTest::requestComplete); + + capture_->streamOn(); + if (camera_->start()) { + cout << "Failed to start camera" << endl; + return TestFail; + } + + for (Request *request : requests) { + if (camera_->queueRequest(request)) { + cout << "Failed to queue request" << endl; + camera_->stop(); + capture_->streamOff(); + cleanup(); + return TestFail; + } + } + + EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher(); + + Timer timer; + timer.start(2000); + while (timer.isRunning()) + dispatcher->processEvents(); + + if (camera_->stop()) { + cout << "Failed to stop camera" << endl; + return TestFail; + } + + capture_->streamOff(); + + return TestPass; + } + + void cleanup() + { + camera_->freeBuffers(); + + if (camera_) { + camera_->release(); + camera_.reset(); + } + + cm_->stop(); + + V4L2VideoDeviceTest::cleanup(); + } + +private: + CameraManager *cm_; + std::shared_ptr camera_; + std::unique_ptr config_; +}; + +TEST_REGISTER(BufferImportTest); diff --git a/test/v4l2_videodevice/meson.build b/test/v4l2_videodevice/meson.build index 76be5e142bb6..15169abe48d3 100644 --- a/test/v4l2_videodevice/meson.build +++ b/test/v4l2_videodevice/meson.build @@ -7,6 +7,7 @@ v4l2_videodevice_tests = [ [ 'stream_on_off', 'stream_on_off.cpp' ], [ 'capture_async', 'capture_async.cpp' ], [ 'buffer_sharing', 'buffer_sharing.cpp' ], + [ 'buffer_import', 'buffer_import.cpp' ], ] foreach t : v4l2_videodevice_tests