From patchwork Thu Aug 29 23:26:53 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: 1901 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 7705560C18 for ; Fri, 30 Aug 2019 01:27:40 +0200 (CEST) X-Halon-ID: 93e34dbb-cab4-11e9-837a-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [79.202.45.17]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 93e34dbb-cab4-11e9-837a-0050569116f7; Fri, 30 Aug 2019 01:27:33 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Fri, 30 Aug 2019 01:26:53 +0200 Message-Id: <20190829232653.13214-15-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.22.1 In-Reply-To: <20190829232653.13214-1-niklas.soderlund@ragnatech.se> References: <20190829232653.13214-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 14/14] 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: Thu, 29 Aug 2019 23:27:40 -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..2bebf0eaf3877641 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 initIPA() 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::initIPA() +{ + 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 parameters"; + + 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 statistics " << 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 statistics " << 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) << "Statistic 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);