From patchwork Mon Mar 11 12:32:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 19659 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 6BADFC32C3 for ; Mon, 11 Mar 2024 12:32:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 33C3E62C80; Mon, 11 Mar 2024 13:32:49 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="kXLaAOa+"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7592562C84 for ; Mon, 11 Mar 2024 13:32:45 +0100 (CET) Received: from localhost.localdomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4F03AF0A; Mon, 11 Mar 2024 13:32:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1710160344; bh=smJtlzff6rYQgdOz9xjdVA74F+C733Ls/z/j3MGeREA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kXLaAOa+GXbX1djUtSf+0ZL3w14hmMUe82Uv50t9QOaKei3glQOJ2YlT0094KWKUY WpvG1aXIRNFfoY/Yvv47S26fw8ZLkEKwvKTudi1VXLj4zGrippcKCpdmL6tzU19dog oRXYOXuRrzT12XNWcRhTlWz06L6zJHX8/tHivsjM= From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Subject: [PATCH v2 3/4] libcamera: ipu3: Replace IPU3FrameInfo Date: Mon, 11 Mar 2024 13:32:31 +0100 Message-ID: <20240311123234.32925-4-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240311123234.32925-1-jacopo.mondi@ideasonboard.com> References: <20240311123234.32925-1-jacopo.mondi@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: , Cc: Jacopo Mondi Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Now that the pipeline handler can create a private derived class of Request::Private, use it to store the pipeline specific data. In the case of IPU3 we associate statistics and paramters buffer with a Request and a raw buffer which gets dequeued from the CIO2 and input to the ImgU input. This replaces the functionalities of IPU3FrameInfo which can now be removed. Signed-off-by: Jacopo Mondi Reviewed-by: Daniel Scally Tested-by: Daniel Scally Reviewed-by: Kieran Bingham --- src/libcamera/pipeline/ipu3/frames.cpp | 143 ---------------- src/libcamera/pipeline/ipu3/frames.h | 67 -------- src/libcamera/pipeline/ipu3/ipu3.cpp | 212 +++++++++++++++--------- src/libcamera/pipeline/ipu3/meson.build | 1 - 4 files changed, 137 insertions(+), 286 deletions(-) delete mode 100644 src/libcamera/pipeline/ipu3/frames.cpp delete mode 100644 src/libcamera/pipeline/ipu3/frames.h diff --git a/src/libcamera/pipeline/ipu3/frames.cpp b/src/libcamera/pipeline/ipu3/frames.cpp deleted file mode 100644 index a4c3477cd9ef..000000000000 --- a/src/libcamera/pipeline/ipu3/frames.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2020, Google Inc. - * - * frames.cpp - Intel IPU3 Frames helper - */ - -#include "frames.h" - -#include -#include - -#include "libcamera/internal/framebuffer.h" -#include "libcamera/internal/pipeline_handler.h" -#include "libcamera/internal/v4l2_videodevice.h" - -namespace libcamera { - -LOG_DECLARE_CATEGORY(IPU3) - -IPU3Frames::IPU3Frames() -{ -} - -void IPU3Frames::init(const std::vector> ¶mBuffers, - const std::vector> &statBuffers) -{ - for (const std::unique_ptr &buffer : paramBuffers) - availableParamBuffers_.push(buffer.get()); - - for (const std::unique_ptr &buffer : statBuffers) - availableStatBuffers_.push(buffer.get()); - - frameInfo_.clear(); -} - -void IPU3Frames::clear() -{ - availableParamBuffers_ = {}; - availableStatBuffers_ = {}; -} - -IPU3Frames::Info *IPU3Frames::create(Request *request) -{ - unsigned int id = request->sequence(); - - if (availableParamBuffers_.empty()) { - LOG(IPU3, Debug) << "Parameters buffer underrun"; - return nullptr; - } - - if (availableStatBuffers_.empty()) { - LOG(IPU3, Debug) << "Statistics buffer underrun"; - return nullptr; - } - - FrameBuffer *paramBuffer = availableParamBuffers_.front(); - FrameBuffer *statBuffer = availableStatBuffers_.front(); - - paramBuffer->_d()->setRequest(request); - statBuffer->_d()->setRequest(request); - - availableParamBuffers_.pop(); - availableStatBuffers_.pop(); - - /* \todo Remove the dynamic allocation of Info */ - std::unique_ptr info = std::make_unique(); - - info->id = id; - info->request = request; - info->rawBuffer = nullptr; - info->paramBuffer = paramBuffer; - info->statBuffer = statBuffer; - info->paramDequeued = false; - info->metadataProcessed = false; - - frameInfo_[id] = std::move(info); - - return frameInfo_[id].get(); -} - -void IPU3Frames::remove(IPU3Frames::Info *info) -{ - /* Return params and stat buffer for reuse. */ - availableParamBuffers_.push(info->paramBuffer); - availableStatBuffers_.push(info->statBuffer); - - /* Delete the extended frame information. */ - frameInfo_.erase(info->id); -} - -bool IPU3Frames::tryComplete(IPU3Frames::Info *info) -{ - Request *request = info->request; - - if (request->hasPendingBuffers()) - return false; - - if (!info->metadataProcessed) - return false; - - if (!info->paramDequeued) - return false; - - remove(info); - - bufferAvailable.emit(); - - return true; -} - -IPU3Frames::Info *IPU3Frames::find(unsigned int id) -{ - const auto &itInfo = frameInfo_.find(id); - - if (itInfo != frameInfo_.end()) - return itInfo->second.get(); - - LOG(IPU3, Fatal) << "Can't find tracking information for frame " << id; - - return nullptr; -} - -IPU3Frames::Info *IPU3Frames::find(FrameBuffer *buffer) -{ - for (auto const &itInfo : frameInfo_) { - Info *info = itInfo.second.get(); - - for (auto const itBuffers : info->request->buffers()) - if (itBuffers.second == buffer) - return info; - - if (info->rawBuffer == buffer || info->paramBuffer == buffer || - info->statBuffer == buffer) - return info; - } - - LOG(IPU3, Fatal) << "Can't find tracking information from buffer"; - - return nullptr; -} - -} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/ipu3/frames.h b/src/libcamera/pipeline/ipu3/frames.h deleted file mode 100644 index 6e3cb915c7b8..000000000000 --- a/src/libcamera/pipeline/ipu3/frames.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2020, Google Inc. - * - * frames.h - Intel IPU3 Frames helper - */ - -#pragma once - -#include -#include -#include -#include - -#include - -#include - -namespace libcamera { - -class FrameBuffer; -class IPAProxy; -class PipelineHandler; -class Request; -class V4L2VideoDevice; -struct IPABuffer; - -class IPU3Frames -{ -public: - struct Info { - unsigned int id; - Request *request; - - FrameBuffer *rawBuffer; - FrameBuffer *paramBuffer; - FrameBuffer *statBuffer; - - ControlList effectiveSensorControls; - - bool paramDequeued; - bool metadataProcessed; - }; - - IPU3Frames(); - - void init(const std::vector> ¶mBuffers, - const std::vector> &statBuffers); - void clear(); - - Info *create(Request *request); - void remove(Info *info); - bool tryComplete(Info *info); - - Info *find(unsigned int id); - Info *find(FrameBuffer *buffer); - - Signal<> bufferAvailable; - -private: - std::queue availableParamBuffers_; - std::queue availableStatBuffers_; - - std::map> frameInfo_; -}; - -} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index fa4bd0bb73e2..0c9d3167d2e6 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -34,9 +34,9 @@ #include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/pipeline_handler.h" +#include "libcamera/internal/request.h" #include "cio2.h" -#include "frames.h" #include "imgu.h" namespace libcamera { @@ -47,6 +47,24 @@ static const ControlInfoMap::Map IPU3Controls = { { &controls::draft::PipelineDepth, ControlInfo(2, 3) }, }; +class IPU3Request : public Request::Private +{ +public: + IPU3Request(Camera *camera) + : Request::Private(camera) + { + } + + FrameBuffer *rawBuffer; + FrameBuffer *paramBuffer; + FrameBuffer *statBuffer; + + ControlList effectiveSensorControls; + + bool paramDequeued; + bool metadataProcessed; +}; + class IPU3CameraData : public Camera::Private { public: @@ -57,6 +75,7 @@ public: int loadIPA(); + void tryCompleteRequest(IPU3Request *request); void imguOutputBufferReady(FrameBuffer *buffer); void cio2BufferReady(FrameBuffer *buffer); void paramBufferReady(FrameBuffer *buffer); @@ -75,7 +94,6 @@ public: Rectangle cropRegion_; std::unique_ptr delayedCtrls_; - IPU3Frames frameInfos_; std::unique_ptr ipa_; @@ -86,7 +104,17 @@ public: ControlInfoMap ipaControls_; + std::map requestMap_; + + std::queue availableParamBuffers_; + std::queue availableStatBuffers_; + private: + IPU3Request *cameraRequest(Request *request) + { + return static_cast(request->_d()); + } + void metadataReady(unsigned int id, const ControlList &metadata); void paramsBufferReady(unsigned int id); void setSensorControls(unsigned int id, const ControlList &sensorControls, @@ -144,6 +172,8 @@ public: int start(Camera *camera, const ControlList *controls) override; void stopDevice(Camera *camera) override; + std::unique_ptr createRequestDevice(Camera *camera, + uint64_t cookie) override; int queueRequestDevice(Camera *camera, Request *request) override; bool match(DeviceEnumerator *enumerator) override; @@ -680,19 +710,17 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera) for (const std::unique_ptr &buffer : imgu->paramBuffers_) { buffer->setCookie(ipaBufferId++); ipaBuffers_.emplace_back(buffer->cookie(), buffer->planes()); + data->availableParamBuffers_.push(buffer.get()); } for (const std::unique_ptr &buffer : imgu->statBuffers_) { buffer->setCookie(ipaBufferId++); ipaBuffers_.emplace_back(buffer->cookie(), buffer->planes()); + data->availableStatBuffers_.push(buffer.get()); } data->ipa_->mapBuffers(ipaBuffers_); - data->frameInfos_.init(imgu->paramBuffers_, imgu->statBuffers_); - data->frameInfos_.bufferAvailable.connect( - data, &IPU3CameraData::queuePendingRequests); - return 0; } @@ -700,8 +728,6 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera) { IPU3CameraData *data = cameraData(camera); - data->frameInfos_.clear(); - std::vector ids; for (IPABuffer &ipabuf : ipaBuffers_) ids.push_back(ipabuf.id); @@ -777,6 +803,7 @@ void PipelineHandlerIPU3::stopDevice(Camera *camera) LOG(IPU3, Warning) << "Failed to stop camera " << camera->id(); freeBuffers(camera); + data->requestMap_.clear(); } void IPU3CameraData::cancelPendingRequests() @@ -801,37 +828,76 @@ void IPU3CameraData::queuePendingRequests() { while (!pendingRequests_.empty()) { Request *request = pendingRequests_.front(); + IPU3Request *ipu3Request = cameraRequest(request); - IPU3Frames::Info *info = frameInfos_.create(request); - if (!info) - break; + requestMap_[request->sequence()] = ipu3Request; /* * Queue a buffer on the CIO2, using the raw stream buffer * provided in the request, if any, or a CIO2 internal buffer * otherwise. + * + * No need to set a buffer->setRequest() as + * a) If the buffer is provided by the application that's + * already been done + * b) If the buffer comes from the CIO2 internal pool, + * CIO2Device::queueBuffer() does that for us */ FrameBuffer *reqRawBuffer = request->findBuffer(&rawStream_); FrameBuffer *rawBuffer = cio2_.queueBuffer(request, reqRawBuffer); + /* * \todo If queueBuffer fails in queuing a buffer to the device, * report the request as error by cancelling the request and * calling PipelineHandler::completeRequest(). */ - if (!rawBuffer) { - frameInfos_.remove(info); + if (!rawBuffer) + break; + + /* + * Store the raw buffer queued to the CIO2 to queue it to the + * Imgu input when the IPA has prepared the parameters buffer. + */ + ipu3Request->rawBuffer = rawBuffer; + + /* + * Prepare the stats and parameters buffer and associate them + * with the currently queued request. + */ + if (availableParamBuffers_.empty()) { + LOG(IPU3, Warning) << "Parameters buffer underrun"; break; } - info->rawBuffer = rawBuffer; + if (availableStatBuffers_.empty()) { + LOG(IPU3, Warning) << "Statistics buffer underrun"; + break; + } - ipa_->queueRequest(info->id, request->controls()); + ipu3Request->paramBuffer = availableParamBuffers_.front(); + ipu3Request->paramDequeued = false; + ipu3Request->paramBuffer->_d()->setRequest(request); + availableParamBuffers_.pop(); + + ipu3Request->statBuffer = availableStatBuffers_.front(); + ipu3Request->metadataProcessed = false; + ipu3Request->statBuffer->_d()->setRequest(request); + availableStatBuffers_.pop(); + + ipa_->queueRequest(request->sequence(), request->controls()); pendingRequests_.pop(); processingRequests_.push(request); } } +std::unique_ptr PipelineHandlerIPU3::createRequestDevice(Camera *camera, + uint64_t cookie) +{ + auto request = std::make_unique(camera); + return Request::create(std::move(request), cookie); +} + int PipelineHandlerIPU3::queueRequestDevice(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); @@ -1200,6 +1266,26 @@ int IPU3CameraData::loadIPA() return 0; } +void IPU3CameraData::tryCompleteRequest(IPU3Request *request) +{ + if (request->hasPendingBuffers()) + return; + + if (!request->metadataProcessed) + return; + + if (!request->paramDequeued) + return; + + availableParamBuffers_.push(request->paramBuffer); + availableStatBuffers_.push(request->statBuffer); + + pipe()->completeRequest(request->_o()); + + /* Try queue another request now that this one has completed. */ + queuePendingRequests(); +} + void IPU3CameraData::setSensorControls([[maybe_unused]] unsigned int id, const ControlList &sensorControls, const ControlList &lensControls) @@ -1220,12 +1306,10 @@ void IPU3CameraData::setSensorControls([[maybe_unused]] unsigned int id, void IPU3CameraData::paramsBufferReady(unsigned int id) { - IPU3Frames::Info *info = frameInfos_.find(id); - if (!info) - return; + IPU3Request *request = requestMap_[id]; /* Queue all buffers from the request aimed for the ImgU. */ - for (auto it : info->request->buffers()) { + for (auto it : request->_o()->buffers()) { const Stream *stream = it.first; FrameBuffer *outbuffer = it.second; @@ -1235,25 +1319,21 @@ void IPU3CameraData::paramsBufferReady(unsigned int id) imgu_->viewfinder_->queueBuffer(outbuffer); } - info->paramBuffer->_d()->metadata().planes()[0].bytesused = + request->paramBuffer->_d()->metadata().planes()[0].bytesused = sizeof(struct ipu3_uapi_params); - imgu_->param_->queueBuffer(info->paramBuffer); - imgu_->stat_->queueBuffer(info->statBuffer); - imgu_->input_->queueBuffer(info->rawBuffer); + imgu_->param_->queueBuffer(request->paramBuffer); + imgu_->stat_->queueBuffer(request->statBuffer); + imgu_->input_->queueBuffer(request->rawBuffer); } void IPU3CameraData::metadataReady(unsigned int id, const ControlList &metadata) { - IPU3Frames::Info *info = frameInfos_.find(id); - if (!info) - return; + IPU3Request *request = requestMap_[id]; - Request *request = info->request; - request->metadata().merge(metadata); + request->_o()->metadata().merge(metadata); - info->metadataProcessed = true; - if (frameInfos_.tryComplete(info)) - pipe()->completeRequest(request); + request->metadataProcessed = true; + tryCompleteRequest(request); } /* ----------------------------------------------------------------------------- @@ -1268,11 +1348,7 @@ void IPU3CameraData::metadataReady(unsigned int id, const ControlList &metadata) */ void IPU3CameraData::imguOutputBufferReady(FrameBuffer *buffer) { - IPU3Frames::Info *info = frameInfos_.find(buffer); - if (!info) - return; - - Request *request = info->request; + Request *request = buffer->request(); pipe()->completeBuffer(request, buffer); @@ -1283,8 +1359,7 @@ void IPU3CameraData::imguOutputBufferReady(FrameBuffer *buffer) cropRegion_ = *scalerCrop; request->metadata().set(controls::ScalerCrop, cropRegion_); - if (frameInfos_.tryComplete(info)) - pipe()->completeRequest(request); + tryCompleteRequest(cameraRequest(request)); } /** @@ -1296,22 +1371,20 @@ void IPU3CameraData::imguOutputBufferReady(FrameBuffer *buffer) */ void IPU3CameraData::cio2BufferReady(FrameBuffer *buffer) { - IPU3Frames::Info *info = frameInfos_.find(buffer); - if (!info) - return; - - Request *request = info->request; + IPU3Request *request = cameraRequest(buffer->request()); /* If the buffer is cancelled force a complete of the whole request. */ if (buffer->metadata().status == FrameMetadata::FrameCancelled) { - for (auto it : request->buffers()) { + for (auto it : request->_o()->buffers()) { FrameBuffer *b = it.second; b->_d()->cancel(); - pipe()->completeBuffer(request, b); + pipe()->completeBuffer(request->_o(), b); } - frameInfos_.remove(info); - pipe()->completeRequest(request); + availableParamBuffers_.push(request->paramBuffer); + availableStatBuffers_.push(request->statBuffer); + + pipe()->completeRequest(request->_o()); return; } @@ -1321,24 +1394,23 @@ void IPU3CameraData::cio2BufferReady(FrameBuffer *buffer) * \todo The sensor timestamp should be better estimated by connecting * to the V4L2Device::frameStart signal. */ - request->metadata().set(controls::SensorTimestamp, - buffer->metadata().timestamp); + request->_o()->metadata().set(controls::SensorTimestamp, + buffer->metadata().timestamp); - info->effectiveSensorControls = delayedCtrls_->get(buffer->metadata().sequence); + request->effectiveSensorControls = + delayedCtrls_->get(buffer->metadata().sequence); - if (request->findBuffer(&rawStream_)) - pipe()->completeBuffer(request, buffer); + if (request->_o()->findBuffer(&rawStream_)) + pipe()->completeBuffer(request->_o(), buffer); - ipa_->fillParamsBuffer(info->id, info->paramBuffer->cookie()); + ipa_->fillParamsBuffer(request->_o()->sequence(), + request->paramBuffer->cookie()); } void IPU3CameraData::paramBufferReady(FrameBuffer *buffer) { - IPU3Frames::Info *info = frameInfos_.find(buffer); - if (!info) - return; - - info->paramDequeued = true; + IPU3Request *request = cameraRequest(buffer->request()); + request->paramDequeued = true; /* * tryComplete() will delete info if it completes the IPU3Frame. @@ -1346,35 +1418,25 @@ void IPU3CameraData::paramBufferReady(FrameBuffer *buffer) * * \todo Improve the FrameInfo API to avoid this type of issue */ - Request *request = info->request; - if (frameInfos_.tryComplete(info)) - pipe()->completeRequest(request); + tryCompleteRequest(request); } void IPU3CameraData::statBufferReady(FrameBuffer *buffer) { - IPU3Frames::Info *info = frameInfos_.find(buffer); - if (!info) - return; - - Request *request = info->request; + IPU3Request *request = cameraRequest(buffer->request()); if (buffer->metadata().status == FrameMetadata::FrameCancelled) { - info->metadataProcessed = true; + request->metadataProcessed = true; - /* - * tryComplete() will delete info if it completes the IPU3Frame. - * In that event, we must have obtained the Request before hand. - */ - if (frameInfos_.tryComplete(info)) - pipe()->completeRequest(request); + tryCompleteRequest(request); return; } - ipa_->processStatsBuffer(info->id, request->metadata().get(controls::SensorTimestamp).value_or(0), - info->statBuffer->cookie(), info->effectiveSensorControls); + ipa_->processStatsBuffer(request->_o()->sequence(), + request->_o()->metadata().get(controls::SensorTimestamp).value_or(0), + request->statBuffer->cookie(), request->effectiveSensorControls); } /* diff --git a/src/libcamera/pipeline/ipu3/meson.build b/src/libcamera/pipeline/ipu3/meson.build index a1b0b31ac5bc..d60e07ae6cca 100644 --- a/src/libcamera/pipeline/ipu3/meson.build +++ b/src/libcamera/pipeline/ipu3/meson.build @@ -2,7 +2,6 @@ libcamera_sources += files([ 'cio2.cpp', - 'frames.cpp', 'imgu.cpp', 'ipu3.cpp', ])