From patchwork Tue Aug 31 22:37:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= X-Patchwork-Id: 13587 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 B5B23C3241 for ; Tue, 31 Aug 2021 22:37:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 512FA6917B; Wed, 1 Sep 2021 00:37:45 +0200 (CEST) Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5DCF560258 for ; Wed, 1 Sep 2021 00:37:31 +0200 (CEST) Received: from localhost.localdomain (unknown [IPv6:2804:14c:1a9:2434:b693:c9:5cb6:b688]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: nfraprado) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 7E4101F43851; Tue, 31 Aug 2021 23:37:29 +0100 (BST) From: =?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= To: libcamera-devel@lists.libcamera.org Date: Tue, 31 Aug 2021 19:37:01 -0300 Message-Id: <20210831223705.1928000-2-nfraprado@collabora.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210831223705.1928000-1-nfraprado@collabora.com> References: <20210831223705.1928000-1-nfraprado@collabora.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 1/5] libcamera: pipeline: vimc: Add internal request queue 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: kernel@collabora.com, =?utf-8?q?Andr=C3=A9_Almeida?= Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add an internal queue that stores requests until there are V4L2 buffer slots available. This avoids the need to cancel requests when there is a shortage of said buffers. Signed-off-by: NĂ­colas F. R. A. Prado --- Changes in v2: - Moved processControls() from PipelineHandlerVimc to VimcCameraData - Moved cancellation of pending requests to after video devices stop - Added a counter to keep track of the number of available buffer slots - Added error log on failure to process controls src/libcamera/pipeline/vimc/vimc.cpp | 167 +++++++++++++++++++-------- 1 file changed, 116 insertions(+), 51 deletions(-) diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index ad71bfc67228..d8f88000d9d7 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,11 @@ public: void bufferReady(FrameBuffer *buffer); void paramsFilled(unsigned int id); + void queuePendingRequests(); + void cancelPendingRequests(); + + void setAvailableBufferSlotCount(unsigned int count) { availableBufferSlotCount_ = count; } + MediaDevice *media_; std::unique_ptr sensor_; std::unique_ptr debayer_; @@ -66,6 +72,13 @@ public: std::unique_ptr ipa_; std::vector> mockIPABufs_; + + std::queue pendingRequests_; + +private: + int processControls(Request *request); + + unsigned int availableBufferSlotCount_; }; class VimcCameraConfiguration : public CameraConfiguration @@ -99,8 +112,6 @@ public: bool match(DeviceEnumerator *enumerator) override; private: - int processControls(VimcCameraData *data, Request *request); - VimcCameraData *cameraData(Camera *camera) { return static_cast(camera->_d()); @@ -335,6 +346,8 @@ int PipelineHandlerVimc::start(Camera *camera, [[maybe_unused]] const ControlLis if (ret < 0) return ret; + data->setAvailableBufferSlotCount(kVimcBufferSlotCount); + /* Map the mock IPA buffers to VIMC IPA to exercise IPC code paths. */ std::vector ipaBuffers; for (auto [i, buffer] : utils::enumerate(data->mockIPABufs_)) { @@ -370,67 +383,24 @@ void PipelineHandlerVimc::stop(Camera *camera) data->ipa_->unmapBuffers(ids); data->ipa_->stop(); - data->video_->releaseBuffers(); -} - -int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request) -{ - ControlList controls(data->sensor_->controls()); - - for (auto it : request->controls()) { - unsigned int id = it.first; - unsigned int offset; - uint32_t cid; + data->cancelPendingRequests(); - if (id == controls::Brightness) { - cid = V4L2_CID_BRIGHTNESS; - offset = 128; - } else if (id == controls::Contrast) { - cid = V4L2_CID_CONTRAST; - offset = 0; - } else if (id == controls::Saturation) { - cid = V4L2_CID_SATURATION; - offset = 0; - } else { - continue; - } - - int32_t value = lroundf(it.second.get() * 128 + offset); - controls.set(cid, std::clamp(value, 0, 255)); - } - - for (const auto &ctrl : controls) - LOG(VIMC, Debug) - << "Setting control " << utils::hex(ctrl.first) - << " to " << ctrl.second.toString(); - - int ret = data->sensor_->setControls(&controls); - if (ret) { - LOG(VIMC, Error) << "Failed to set controls: " << ret; - return ret < 0 ? ret : -EINVAL; - } - - return ret; + data->video_->releaseBuffers(); } int PipelineHandlerVimc::queueRequestDevice(Camera *camera, Request *request) { VimcCameraData *data = cameraData(camera); - FrameBuffer *buffer = request->findBuffer(&data->stream_); - if (!buffer) { + + if (!request->findBuffer(&data->stream_)) { LOG(VIMC, Error) << "Attempt to queue request with invalid stream"; return -ENOENT; } - int ret = processControls(data, request); - if (ret < 0) - return ret; - - ret = data->video_->queueBuffer(buffer); - if (ret < 0) - return ret; + data->pendingRequests_.push(request); + data->queuePendingRequests(); data->ipa_->processControls(request->sequence(), request->controls()); @@ -565,6 +535,46 @@ int VimcCameraData::init() return 0; } +int VimcCameraData::processControls(Request *request) +{ + ControlList controls(sensor_->controls()); + + for (auto it : request->controls()) { + unsigned int id = it.first; + unsigned int offset; + uint32_t cid; + + if (id == controls::Brightness) { + cid = V4L2_CID_BRIGHTNESS; + offset = 128; + } else if (id == controls::Contrast) { + cid = V4L2_CID_CONTRAST; + offset = 0; + } else if (id == controls::Saturation) { + cid = V4L2_CID_SATURATION; + offset = 0; + } else { + continue; + } + + int32_t value = lroundf(it.second.get() * 128 + offset); + controls.set(cid, std::clamp(value, 0, 255)); + } + + for (const auto &ctrl : controls) + LOG(VIMC, Debug) + << "Setting control " << utils::hex(ctrl.first) + << " to " << ctrl.second.toString(); + + int ret = sensor_->setControls(&controls); + if (ret) { + LOG(VIMC, Error) << "Failed to set controls: " << ret; + return ret < 0 ? ret : -EINVAL; + } + + return ret; +} + void VimcCameraData::bufferReady(FrameBuffer *buffer) { PipelineHandlerVimc *pipe = @@ -591,6 +601,10 @@ void VimcCameraData::bufferReady(FrameBuffer *buffer) pipe->completeRequest(request); ipa_->fillParams(request->sequence(), mockIPABufs_[0]->cookie()); + + availableBufferSlotCount_++; + + queuePendingRequests(); } int VimcCameraData::allocateMockIPABuffers() @@ -612,6 +626,57 @@ void VimcCameraData::paramsFilled([[maybe_unused]] unsigned int id) { } +void VimcCameraData::queuePendingRequests() +{ + while (!pendingRequests_.empty() && availableBufferSlotCount_) { + Request *request = pendingRequests_.front(); + FrameBuffer *buffer = request->findBuffer(&stream_); + + int ret = processControls(request); + if (ret < 0) { + LOG(VIMC, Error) << "Failed to process controls with" + << " error " << ret << ". Cancelling" + << " buffer."; + buffer->cancel(); + pipe()->completeBuffer(request, buffer); + pipe()->completeRequest(request); + pendingRequests_.pop(); + + continue; + } + + ret = video_->queueBuffer(buffer); + if (ret < 0) { + LOG(VIMC, Error) << "Failed to queue buffer with error " + << ret << ". Cancelling buffer."; + buffer->cancel(); + pipe()->completeBuffer(request, buffer); + pipe()->completeRequest(request); + pendingRequests_.pop(); + + continue; + } + + availableBufferSlotCount_--; + + pendingRequests_.pop(); + } +} + +void VimcCameraData::cancelPendingRequests() +{ + while (!pendingRequests_.empty()) { + Request *request = pendingRequests_.front(); + FrameBuffer *buffer = request->findBuffer(&stream_); + + buffer->cancel(); + pipe()->completeBuffer(request, buffer); + pipe()->completeRequest(request); + + pendingRequests_.pop(); + } +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerVimc) } /* namespace libcamera */