From patchwork Wed Aug 28 01:17:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1878 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 81DD860C37 for ; Wed, 28 Aug 2019 03:17:57 +0200 (CEST) X-Halon-ID: a0d1dcf7-c931-11e9-bdc3-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [95.195.154.80]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id a0d1dcf7-c931-11e9-bdc3-005056917a89; Wed, 28 Aug 2019 03:17:41 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 28 Aug 2019 03:17:10 +0200 Message-Id: <20190828011710.32128-14-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.22.1 In-Reply-To: <20190828011710.32128-1-niklas.soderlund@ragnatech.se> References: <20190828011710.32128-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 13/13] libcamera: pipeline: rkisp1: Attach to an IPA 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: Wed, 28 Aug 2019 01:17:57 -0000 Add the plumbing to the pipeline handler to interact with an IPA module. To support this parameter and statistic buffers needs to be associated with every request queued. The parameters buffer needs to be passed to the IPA before any buffer in the request is queued to hardware and the statistics buffer needs to be passed to the IPA for inspection as soon as it's ready. This change makes the usage of an IPA module mandatory for the rkisp1 pipeline. Signed-off-by: Niklas Söderlund --- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 263 ++++++++++++++++++++++- 1 file changed, 252 insertions(+), 11 deletions(-) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index de4ab523d0e4fe36..80d4832c49ebe78c 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include @@ -34,7 +34,7 @@ class RkISP1CameraData : public CameraData { public: RkISP1CameraData(PipelineHandler *pipe) - : CameraData(pipe), sensor_(nullptr) + : CameraData(pipe, 1, 1), sensor_(nullptr) { } @@ -43,8 +43,21 @@ public: delete sensor_; } + int initCameraData() override; + Stream stream_; CameraSensor *sensor_; + +private: + void updateSensor(V4L2ControlList controls); + void queueRequestHardware(const void *cookie); +}; + +class RkISP1RequestData : public RequestData +{ +public: + Buffer *stat; + Buffer *param; }; class RkISP1CameraConfiguration : public CameraConfiguration @@ -99,18 +112,69 @@ private: PipelineHandler::cameraData(camera)); } + friend RkISP1CameraData; + int initLinks(); int createCamera(MediaEntity *sensor); + void tryCompleteRequest(Request *request); void bufferReady(Buffer *buffer); + void statReady(Buffer *buffer); + void paramReady(Buffer *buffer); MediaDevice *media_; V4L2Subdevice *dphy_; V4L2Subdevice *isp_; V4L2VideoDevice *video_; + V4L2VideoDevice *stat_; + V4L2VideoDevice *param_; + + BufferPool statPool_; + BufferPool paramPool_; + + std::queue statBuffers_; + std::queue paramBuffers_; Camera *activeCamera_; }; +int RkISP1CameraData::initCameraData() +{ + ipa_->updateSensor.connect(this, + &RkISP1CameraData::updateSensor); + ipa_->queueRequest.connect(this, + &RkISP1CameraData::queueRequestHardware); + return 0; +} + +void RkISP1CameraData::updateSensor(V4L2ControlList controls) +{ + sensor_->setControls(&controls); +} + +void RkISP1CameraData::queueRequestHardware(const void *cookie) +{ + /* Translate cookie to request. */ + Request *request = reinterpret_cast(const_cast(cookie)); + PipelineHandlerRkISP1 *pipe = + static_cast(pipe_); + RkISP1RequestData *reqData = + static_cast(request->data); + Buffer *buffer = request->findBuffer(&stream_); + int ret; + + ret = pipe->param_->queueBuffer(reqData->param); + if (ret < 0) + LOG(RkISP1, Error) << "Failed to queue paramaeters"; + + ret = pipe->stat_->queueBuffer(reqData->stat); + if (ret < 0) + LOG(RkISP1, Error) << "Failed to queue statistics"; + + ret = pipe->video_->queueBuffer(buffer); + if (ret < 0) + LOG(RkISP1, Error) << "Failed to queue video"; +} + RkISP1CameraConfiguration::RkISP1CameraConfiguration(Camera *camera, RkISP1CameraData *data) : CameraConfiguration() @@ -202,12 +266,14 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() PipelineHandlerRkISP1::PipelineHandlerRkISP1(CameraManager *manager) : PipelineHandler(manager), dphy_(nullptr), isp_(nullptr), - video_(nullptr) + video_(nullptr), stat_(nullptr), param_(nullptr) { } PipelineHandlerRkISP1::~PipelineHandlerRkISP1() { + delete param_; + delete stat_; delete video_; delete isp_; delete dphy_; @@ -317,6 +383,20 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c) if (ret) return ret; + V4L2DeviceFormat statFormat = {}; + statFormat.fourcc = V4L2_META_FMT_RK_ISP1_STAT_3A; + + ret = stat_->setFormat(&statFormat); + if (ret) + return ret; + + V4L2DeviceFormat paramFormat = {}; + paramFormat.fourcc = V4L2_META_FMT_RK_ISP1_PARAMS; + + ret = param_->setFormat(¶mFormat); + if (ret) + return ret; + if (outputFormat.size != cfg.size || outputFormat.fourcc != cfg.pixelFormat) { LOG(RkISP1, Error) @@ -333,30 +413,92 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera, const std::set &streams) { Stream *stream = *streams.begin(); + int ret; if (stream->memoryType() == InternalMemory) - return video_->exportBuffers(&stream->bufferPool()); + ret = video_->exportBuffers(&stream->bufferPool()); else - return video_->importBuffers(&stream->bufferPool()); + ret = video_->importBuffers(&stream->bufferPool()); + + if (ret) + return ret; + + statPool_.createBuffers(stream->configuration().bufferCount); + ret = stat_->exportBuffers(&statPool_); + if (ret) { + video_->releaseBuffers(); + return ret; + } + + paramPool_.createBuffers(stream->configuration().bufferCount); + ret = param_->exportBuffers(¶mPool_); + if (ret) { + stat_->releaseBuffers(); + video_->releaseBuffers(); + return ret; + } + + for (unsigned int i = 0; i < stream->configuration().bufferCount; i++) { + statBuffers_.push(new Buffer(i)); + paramBuffers_.push(new Buffer(i)); + } + + return ret; } int PipelineHandlerRkISP1::freeBuffers(Camera *camera, const std::set &streams) { + while (!paramBuffers_.empty()) + paramBuffers_.pop(); + + while (!statBuffers_.empty()) + statBuffers_.pop(); + + if (param_->releaseBuffers()) + LOG(RkISP1, Error) << "Failed to release parameters buffers"; + + if (stat_->releaseBuffers()) + LOG(RkISP1, Error) << "Failed to release stat buffers"; + if (video_->releaseBuffers()) - LOG(RkISP1, Error) << "Failed to release buffers"; + LOG(RkISP1, Error) << "Failed to release video buffers"; return 0; } int PipelineHandlerRkISP1::start(Camera *camera) { + RkISP1CameraData *data = cameraData(camera); int ret; + ret = data->ipa_->initSensor(data->sensor_->controls()); + if (ret) + return ret; + + ret = param_->streamOn(); + if (ret) { + LOG(RkISP1, Error) + << "Failed to start parameters " << camera->name(); + return ret; + } + + ret = stat_->streamOn(); + if (ret) { + param_->streamOff(); + LOG(RkISP1, Error) + << "Failed to start statisticis " << camera->name(); + return ret; + } + ret = video_->streamOn(); - if (ret) + if (ret) { + param_->streamOff(); + stat_->streamOff(); + LOG(RkISP1, Error) << "Failed to start camera " << camera->name(); + } activeCamera_ = camera; @@ -372,6 +514,16 @@ void PipelineHandlerRkISP1::stop(Camera *camera) LOG(RkISP1, Warning) << "Failed to stop camera " << camera->name(); + ret = stat_->streamOff(); + if (ret) + LOG(RkISP1, Warning) + << "Failed to stop statisticis " << camera->name(); + + ret = param_->streamOff(); + if (ret) + LOG(RkISP1, Warning) + << "Failed to stop parameters " << camera->name(); + activeCamera_ = nullptr; } @@ -380,6 +532,16 @@ int PipelineHandlerRkISP1::queueRequest(Camera *camera, Request *request) RkISP1CameraData *data = cameraData(camera); Stream *stream = &data->stream_; + if (paramBuffers_.empty()) { + LOG(RkISP1, Error) << "Parameters buffer underrun"; + return -ENOENT; + } + + if (statBuffers_.empty()) { + LOG(RkISP1, Error) << "Statisitc buffer underrun"; + return -ENOENT; + } + Buffer *buffer = request->findBuffer(stream); if (!buffer) { LOG(RkISP1, Error) @@ -387,12 +549,24 @@ int PipelineHandlerRkISP1::queueRequest(Camera *camera, Request *request) return -ENOENT; } - int ret = video_->queueBuffer(buffer); - if (ret < 0) - return ret; + RkISP1RequestData *reqData = new RkISP1RequestData(); + request->data = reqData; + reqData->param = paramBuffers_.front(); + reqData->stat = statBuffers_.front(); + + prepareInternalBuffer(reqData->param, request, + ¶mPool_.buffers()[reqData->param->index()]); + prepareInternalBuffer(reqData->stat, request, + &statPool_.buffers()[reqData->stat->index()]); + + paramBuffers_.pop(); + statBuffers_.pop(); PipelineHandler::queueRequest(camera, request); + data->ipa_->processRequest(request, request->controls(), + *reqData->param); + return 0; } @@ -435,6 +609,10 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) std::unique_ptr data = utils::make_unique(this); + data->controlInfo_.emplace(std::piecewise_construct, + std::forward_as_tuple(AeEnable), + std::forward_as_tuple(AeEnable, false, true)); + data->sensor_ = new CameraSensor(sensor); ret = data->sensor_->init(); if (ret) @@ -478,7 +656,17 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator) if (video_->open() < 0) return false; + stat_ = V4L2VideoDevice::fromEntityName(media_, "rkisp1-statistics"); + if (stat_->open() < 0) + return false; + + param_ = V4L2VideoDevice::fromEntityName(media_, "rkisp1-input-params"); + if (param_->open() < 0) + return false; + video_->bufferReady.connect(this, &PipelineHandlerRkISP1::bufferReady); + stat_->bufferReady.connect(this, &PipelineHandlerRkISP1::statReady); + param_->bufferReady.connect(this, &PipelineHandlerRkISP1::paramReady); /* Configure default links. */ if (initLinks() < 0) { @@ -504,13 +692,66 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator) * Buffer Handling */ +void PipelineHandlerRkISP1::tryCompleteRequest(Request *request) +{ + RkISP1RequestData *reqData = + static_cast(request->data); + + if (reqData->param) + return; + + if (reqData->stat) + return; + + if (request->hasPendingBuffers()) + return; + + delete reqData; + request->data = nullptr; + + completeRequest(activeCamera_, request); +} + void PipelineHandlerRkISP1::bufferReady(Buffer *buffer) { ASSERT(activeCamera_); Request *request = buffer->request(); completeBuffer(activeCamera_, request, buffer); - completeRequest(activeCamera_, request); + tryCompleteRequest(request); +} + +void PipelineHandlerRkISP1::statReady(Buffer *buffer) +{ + ASSERT(activeCamera_); + RkISP1CameraData *data = cameraData(activeCamera_); + Request *request = buffer->request(); + RkISP1RequestData *reqData = + static_cast(request->data); + + data->ipa_->updateStatistics(request, *buffer); + + /* TODO: Fetch libcamera status controls from IPA */ + + reqData->stat = nullptr; + + statBuffers_.push(buffer); + + tryCompleteRequest(request); +} + +void PipelineHandlerRkISP1::paramReady(Buffer *buffer) +{ + ASSERT(activeCamera_); + Request *request = buffer->request(); + RkISP1RequestData *reqData = + static_cast(request->data); + + reqData->param = nullptr; + + paramBuffers_.push(buffer); + + tryCompleteRequest(request); } REGISTER_PIPELINE_HANDLER(PipelineHandlerRkISP1);