From patchwork Fri Nov 15 12:25:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Scally X-Patchwork-Id: 21922 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 0162FC32CE for ; Fri, 15 Nov 2024 12:26:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E54BC6589A; Fri, 15 Nov 2024 13:26:39 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="AyyRgM2w"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C537C6580A for ; Fri, 15 Nov 2024 13:26:34 +0100 (CET) Received: from mail.ideasonboard.com (cpc141996-chfd3-2-0-cust928.12-3.cable.virginm.net [86.13.91.161]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 206986BE; Fri, 15 Nov 2024 13:26:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1731673580; bh=zyukOom0oI0pFXRLHejkkDoEmz1rr1NDIKHLs2geRSw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AyyRgM2wdp5/QeJD/3xgfcI9YH6vnF7FOq9VYPIaPofJxWBRAC2nAcKw8Z6Ac4qGQ V/95tHK0LfJqQ3wo5U564paSi5QYrx3KNoGzD6Mlo6AN6hM8yQpU7St0TcAU2sw72k LAFkZvjqE2IRN3WT5iuxC1AtMUI5MzuXnIPXBM7o= From: Daniel Scally To: libcamera-devel@lists.libcamera.org Cc: Anthony.McGivern@arm.com, Daniel Scally , Kieran Bingham , Nayden Kanchev , Jacopo Mondi Subject: [PATCH v4 04/11] libcamera: mali-c55: Acquire and plumb in 3a params and stats Date: Fri, 15 Nov 2024 12:25:33 +0000 Message-Id: <20241115122540.478103-5-dan.scally@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241115122540.478103-1-dan.scally@ideasonboard.com> References: <20241115122540.478103-1-dan.scally@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Acquire the mali-c55 3a stats and parameters video devices during ::match() and plumb them in. For this commit we simply allocate and release buffers for the statistics and parameters. Statistics buffers are queue and dequeued from the stats video device but their contents are for now untouched. Reviewed-by: Kieran Bingham Acked-by: Nayden Kanchev Co-developed-by: Jacopo Mondi Signed-off-by: Jacopo Mondi Signed-off-by: Daniel Scally --- Changes in v4: - None Changes in v3: - None Changes in v2: - Links between the ISP subdevice and the statistics and parameters video devices are now enabled (previously they were immutable) src/libcamera/pipeline/mali-c55/mali-c55.cpp | 153 ++++++++++++++++++- 1 file changed, 150 insertions(+), 3 deletions(-) diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index 3fc07a5d..e451204b 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -28,6 +29,7 @@ #include "libcamera/internal/camera.h" #include "libcamera/internal/camera_sensor.h" #include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/framebuffer.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/v4l2_subdevice.h" @@ -520,6 +522,8 @@ public: int exportFrameBuffers(Camera *camera, Stream *stream, std::vector> *buffers) override; + int allocateBuffers(Camera *camera); + void freeBuffers(Camera *camera); int start(Camera *camera, const ControlList *controls) override; void stopDevice(Camera *camera) override; @@ -527,6 +531,7 @@ public: int queueRequestDevice(Camera *camera, Request *request) override; void imageBufferReady(FrameBuffer *buffer); + void statsBufferReady(FrameBuffer *buffer); bool match(DeviceEnumerator *enumerator) override; @@ -587,6 +592,14 @@ private: MediaDevice *media_; std::unique_ptr isp_; + std::unique_ptr stats_; + std::unique_ptr params_; + + std::vector> statsBuffers_; + std::queue availableStatsBuffers_; + + std::vector> paramsBuffers_; + std::queue availableParamsBuffers_; std::array pipes_; @@ -846,6 +859,16 @@ int PipelineHandlerMaliC55::configure(Camera *camera, return ret; } + V4L2DeviceFormat statsFormat; + ret = stats_->getFormat(&statsFormat); + if (ret) + return ret; + + if (statsFormat.planes[0].size != sizeof(struct mali_c55_stats_buffer)) { + LOG(MaliC55, Error) << "3a stats buffer size invalid"; + return -EINVAL; + } + /* * Propagate the format to the ISP sink pad and configure the input * crop rectangle (no crop at the moment). @@ -921,27 +944,110 @@ int PipelineHandlerMaliC55::exportFrameBuffers(Camera *camera, Stream *stream, return pipe->cap->exportBuffers(count, buffers); } -int PipelineHandlerMaliC55::start([[maybe_unused]] Camera *camera, [[maybe_unused]] const ControlList *controls) +void PipelineHandlerMaliC55::freeBuffers([[maybe_unused]] Camera *camera) +{ + while (!availableStatsBuffers_.empty()) + availableStatsBuffers_.pop(); + while (!availableParamsBuffers_.empty()) + availableParamsBuffers_.pop(); + + statsBuffers_.clear(); + paramsBuffers_.clear(); + + if (stats_->releaseBuffers()) + LOG(MaliC55, Error) << "Failed to release stats buffers"; + + if (params_->releaseBuffers()) + LOG(MaliC55, Error) << "Failed to release stats buffers"; + + return; +} + +int PipelineHandlerMaliC55::allocateBuffers(Camera *camera) +{ + MaliC55CameraData *data = cameraData(camera); + unsigned int bufferCount; + int ret; + + bufferCount = std::max({ + data->frStream_.configuration().bufferCount, + data->dsStream_.configuration().bufferCount, + }); + + ret = stats_->allocateBuffers(bufferCount, &statsBuffers_); + if (ret < 0) + return ret; + + for (std::unique_ptr &buffer : statsBuffers_) + availableStatsBuffers_.push(buffer.get()); + + ret = params_->allocateBuffers(bufferCount, ¶msBuffers_); + if (ret < 0) + return ret; + + for (std::unique_ptr &buffer : paramsBuffers_) + availableParamsBuffers_.push(buffer.get()); + + return 0; +} + +int PipelineHandlerMaliC55::start(Camera *camera, [[maybe_unused]] const ControlList *controls) { + int ret; + + ret = allocateBuffers(camera); + if (ret) + return ret; + for (MaliC55Pipe &pipe : pipes_) { if (!pipe.stream) continue; Stream *stream = pipe.stream; - int ret = pipe.cap->importBuffers(stream->configuration().bufferCount); + ret = pipe.cap->importBuffers(stream->configuration().bufferCount); if (ret) { LOG(MaliC55, Error) << "Failed to import buffers"; + freeBuffers(camera); return ret; } ret = pipe.cap->streamOn(); if (ret) { LOG(MaliC55, Error) << "Failed to start stream"; + freeBuffers(camera); return ret; } } + ret = stats_->streamOn(); + if (ret) { + LOG(MaliC55, Error) << "Failed to start stats stream"; + + for (MaliC55Pipe &pipe : pipes_) { + if (pipe.stream) + pipe.cap->streamOff(); + } + + freeBuffers(camera); + return ret; + } + + ret = params_->streamOn(); + if (ret) { + LOG(MaliC55, Error) << "Failed to start params stream"; + + stats_->streamOff(); + + for (MaliC55Pipe &pipe : pipes_) { + if (pipe.stream) + pipe.cap->streamOff(); + } + + freeBuffers(camera); + return ret; + } + return 0; } @@ -954,6 +1060,10 @@ void PipelineHandlerMaliC55::stopDevice([[maybe_unused]] Camera *camera) pipe.cap->streamOff(); pipe.cap->releaseBuffers(); } + + stats_->streamOff(); + params_->streamOff(); + freeBuffers(camera); } void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera, @@ -1054,8 +1164,24 @@ void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera, int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request) { + FrameBuffer *statsBuffer; int ret; + if (availableStatsBuffers_.empty()) { + LOG(MaliC55, Error) << "Stats buffer underrun"; + return -ENOENT; + } + + statsBuffer = availableStatsBuffers_.front(); + availableStatsBuffers_.pop(); + + /* + * We need to associate the Request to this buffer even though it's a + * purely internal one because we will need to use request->sequence() + * later. + */ + statsBuffer->_d()->setRequest(request); + for (auto &[stream, buffer] : request->buffers()) { MaliC55Pipe *pipe = pipeFromStream(cameraData(camera), stream); @@ -1073,6 +1199,10 @@ int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request) */ applyScalerCrop(camera, request->controls()); + ret = stats_->queueBuffer(statsBuffer); + if (ret) + return ret; + return 0; } @@ -1084,6 +1214,11 @@ void PipelineHandlerMaliC55::imageBufferReady(FrameBuffer *buffer) completeRequest(request); } +void PipelineHandlerMaliC55::statsBufferReady(FrameBuffer *buffer) +{ + availableStatsBuffers_.push(buffer); +} + void PipelineHandlerMaliC55::registerMaliCamera(std::unique_ptr data, const std::string &name) { @@ -1161,7 +1296,7 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator) const MediaPad *ispSink; /* - * We search for just the ISP subdevice and the full resolution pipe. + * We search for just the always-available elements of the media graph. * The TPG and the downscale pipe are both optional blocks and may not * be fitted. */ @@ -1169,6 +1304,8 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator) dm.add("mali-c55 isp"); dm.add("mali-c55 resizer fr"); dm.add("mali-c55 fr"); + dm.add("mali-c55 3a stats"); + dm.add("mali-c55 3a params"); media_ = acquireMediaDevice(enumerator, dm); if (!media_) @@ -1178,6 +1315,14 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator) if (isp_->open() < 0) return false; + stats_ = V4L2VideoDevice::fromEntityName(media_, "mali-c55 3a stats"); + if (stats_->open() < 0) + return false; + + params_ = V4L2VideoDevice::fromEntityName(media_, "mali-c55 3a params"); + if (params_->open() < 0) + return false; + MaliC55Pipe *frPipe = &pipes_[MaliC55FR]; frPipe->resizer = V4L2Subdevice::fromEntityName(media_, "mali-c55 resizer fr"); if (frPipe->resizer->open() < 0) @@ -1219,6 +1364,8 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator) dsPipe->cap->bufferReady.connect(this, &PipelineHandlerMaliC55::imageBufferReady); } + stats_->bufferReady.connect(this, &PipelineHandlerMaliC55::statsBufferReady); + ispSink = isp_->entity()->getPadByIndex(0); if (!ispSink || ispSink->links().empty()) { LOG(MaliC55, Error) << "ISP sink pad error";