[libcamera-devel,3/3] libcamera: pipeline: rkisp1: Add internal request queue
diff mbox series

Message ID 20210719191438.189046-4-nfraprado@collabora.com
State New
Headers show
Series
  • libcamera: pipeline: Add internal request queue
Related show

Commit Message

Nícolas F. R. A. Prado July 19, 2021, 7:14 p.m. UTC
Add an internal queue that stores requests until there are internal
buffers and 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 <nfraprado@collabora.com>
---
 src/libcamera/pipeline/rkisp1/rkisp1.cpp | 73 +++++++++++++++++++-----
 1 file changed, 59 insertions(+), 14 deletions(-)

Comments

Laurent Pinchart Aug. 1, 2021, 10:17 p.m. UTC | #1
Hi Nícolas,

Thank you for the patch.

On Mon, Jul 19, 2021 at 04:14:38PM -0300, Nícolas F. R. A. Prado wrote:
> Add an internal queue that stores requests until there are internal
> buffers and 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 <nfraprado@collabora.com>
> ---
>  src/libcamera/pipeline/rkisp1/rkisp1.cpp | 73 +++++++++++++++++++-----
>  1 file changed, 59 insertions(+), 14 deletions(-)
> 
> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> index f4ea2fd4d4d0..f1c75b7d37c5 100644
> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> @@ -89,6 +89,9 @@ public:
>  
>  	int loadIPA(unsigned int hwRevision);
>  
> +	void queuePendingRequests();
> +	void cancelPendingRequests();
> +
>  	Stream mainPathStream_;
>  	Stream selfPathStream_;
>  	std::unique_ptr<CameraSensor> sensor_;
> @@ -102,6 +105,8 @@ public:
>  
>  	std::unique_ptr<ipa::rkisp1::IPAProxyRkISP1> ipa_;
>  
> +	std::queue<Request *> pendingRequests_;
> +
>  private:
>  	void queueFrameAction(unsigned int frame,
>  			      const ipa::rkisp1::RkISP1Action &action);
> @@ -199,13 +204,13 @@ RkISP1FrameInfo *RkISP1Frames::create(const RkISP1CameraData *data, Request *req
>  	unsigned int frame = data->frame_;
>  
>  	if (pipe_->availableParamBuffers_.empty()) {
> -		LOG(RkISP1, Error) << "Parameters buffer underrun";
> +		LOG(RkISP1, Debug) << "Parameters buffer underrun";
>  		return nullptr;
>  	}
>  	FrameBuffer *paramBuffer = pipe_->availableParamBuffers_.front();
>  
>  	if (pipe_->availableStatBuffers_.empty()) {
> -		LOG(RkISP1, Error) << "Statisitc buffer underrun";
> +		LOG(RkISP1, Debug) << "Statistic buffer underrun";
>  		return nullptr;
>  	}
>  	FrameBuffer *statBuffer = pipe_->availableStatBuffers_.front();
> @@ -373,6 +378,52 @@ void RkISP1CameraData::metadataReady(unsigned int frame, const ControlList &meta
>  	pipe->tryCompleteRequest(info->request);
>  }
>  
> +void RkISP1CameraData::queuePendingRequests()
> +{
> +	while (!pendingRequests_.empty()) {
> +		Request *request = pendingRequests_.front();
> +
> +		/*
> +		 * If there aren't internal buffers available, we break and try
> +		 * again later. If there are, we're guaranteed to also have V4L2
> +		 * buffer slots available to queue the request, since we should
> +		 * always have more (or equal) buffer slots than internal
> +		 * buffers.
> +		 */
> +		RkISP1FrameInfo *info = frameInfo_.create(this, request);
> +		if (!info)
> +			break;
> +
> +		ipa::rkisp1::RkISP1Event ev;
> +		ev.op = ipa::rkisp1::EventQueueRequest;
> +		ev.frame = frame_;
> +		ev.bufferId = info->paramBuffer->cookie();
> +		ev.controls = request->controls();
> +		ipa_->processEvent(ev);
> +
> +		frame_++;
> +
> +		pendingRequests_.pop();
> +	}
> +}
> +
> +void RkISP1CameraData::cancelPendingRequests()
> +{
> +	while (!pendingRequests_.empty()) {
> +		Request *request = pendingRequests_.front();
> +
> +		for (auto it : request->buffers()) {
> +			FrameBuffer *buffer = it.second;
> +			buffer->cancel();
> +			pipe_->completeBuffer(request, buffer);
> +		}
> +
> +		pipe_->completeRequest(request);
> +
> +		pendingRequests_.pop();
> +	}
> +}
> +
>  RkISP1CameraConfiguration::RkISP1CameraConfiguration(Camera *camera,
>  						     RkISP1CameraData *data)
>  	: CameraConfiguration()
> @@ -827,6 +878,8 @@ void PipelineHandlerRkISP1::stop(Camera *camera)
>  
>  	isp_->setFrameStartEnabled(false);
>  
> +	data->cancelPendingRequests();
> +

I was going to say that this should be done after stopping the video
devices, otherwise you'll complete the pending requests out of order,
before the requests that have been queued already, but the pipeline
handler core will reorder the completions, so it should be fine. Still,
if they can be cancelled after stopping the video devices, it would be a
more logical order, so I'd prefer that. Same comment for the other
patches in this series.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

>  	data->ipa_->stop();
>  
>  	selfPath_.stop();
> @@ -854,18 +907,8 @@ int PipelineHandlerRkISP1::queueRequestDevice(Camera *camera, Request *request)
>  {
>  	RkISP1CameraData *data = cameraData(camera);
>  
> -	RkISP1FrameInfo *info = data->frameInfo_.create(data, request);
> -	if (!info)
> -		return -ENOENT;
> -
> -	ipa::rkisp1::RkISP1Event ev;
> -	ev.op = ipa::rkisp1::EventQueueRequest;
> -	ev.frame = data->frame_;
> -	ev.bufferId = info->paramBuffer->cookie();
> -	ev.controls = request->controls();
> -	data->ipa_->processEvent(ev);
> -
> -	data->frame_++;
> +	data->pendingRequests_.push(request);
> +	data->queuePendingRequests();
>  
>  	return 0;
>  }
> @@ -1062,6 +1105,8 @@ void PipelineHandlerRkISP1::tryCompleteRequest(Request *request)
>  	data->frameInfo_.destroy(info->frame);
>  
>  	completeRequest(request);
> +
> +	data->queuePendingRequests();
>  }
>  
>  void PipelineHandlerRkISP1::bufferReady(FrameBuffer *buffer)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index f4ea2fd4d4d0..f1c75b7d37c5 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -89,6 +89,9 @@  public:
 
 	int loadIPA(unsigned int hwRevision);
 
+	void queuePendingRequests();
+	void cancelPendingRequests();
+
 	Stream mainPathStream_;
 	Stream selfPathStream_;
 	std::unique_ptr<CameraSensor> sensor_;
@@ -102,6 +105,8 @@  public:
 
 	std::unique_ptr<ipa::rkisp1::IPAProxyRkISP1> ipa_;
 
+	std::queue<Request *> pendingRequests_;
+
 private:
 	void queueFrameAction(unsigned int frame,
 			      const ipa::rkisp1::RkISP1Action &action);
@@ -199,13 +204,13 @@  RkISP1FrameInfo *RkISP1Frames::create(const RkISP1CameraData *data, Request *req
 	unsigned int frame = data->frame_;
 
 	if (pipe_->availableParamBuffers_.empty()) {
-		LOG(RkISP1, Error) << "Parameters buffer underrun";
+		LOG(RkISP1, Debug) << "Parameters buffer underrun";
 		return nullptr;
 	}
 	FrameBuffer *paramBuffer = pipe_->availableParamBuffers_.front();
 
 	if (pipe_->availableStatBuffers_.empty()) {
-		LOG(RkISP1, Error) << "Statisitc buffer underrun";
+		LOG(RkISP1, Debug) << "Statistic buffer underrun";
 		return nullptr;
 	}
 	FrameBuffer *statBuffer = pipe_->availableStatBuffers_.front();
@@ -373,6 +378,52 @@  void RkISP1CameraData::metadataReady(unsigned int frame, const ControlList &meta
 	pipe->tryCompleteRequest(info->request);
 }
 
+void RkISP1CameraData::queuePendingRequests()
+{
+	while (!pendingRequests_.empty()) {
+		Request *request = pendingRequests_.front();
+
+		/*
+		 * If there aren't internal buffers available, we break and try
+		 * again later. If there are, we're guaranteed to also have V4L2
+		 * buffer slots available to queue the request, since we should
+		 * always have more (or equal) buffer slots than internal
+		 * buffers.
+		 */
+		RkISP1FrameInfo *info = frameInfo_.create(this, request);
+		if (!info)
+			break;
+
+		ipa::rkisp1::RkISP1Event ev;
+		ev.op = ipa::rkisp1::EventQueueRequest;
+		ev.frame = frame_;
+		ev.bufferId = info->paramBuffer->cookie();
+		ev.controls = request->controls();
+		ipa_->processEvent(ev);
+
+		frame_++;
+
+		pendingRequests_.pop();
+	}
+}
+
+void RkISP1CameraData::cancelPendingRequests()
+{
+	while (!pendingRequests_.empty()) {
+		Request *request = pendingRequests_.front();
+
+		for (auto it : request->buffers()) {
+			FrameBuffer *buffer = it.second;
+			buffer->cancel();
+			pipe_->completeBuffer(request, buffer);
+		}
+
+		pipe_->completeRequest(request);
+
+		pendingRequests_.pop();
+	}
+}
+
 RkISP1CameraConfiguration::RkISP1CameraConfiguration(Camera *camera,
 						     RkISP1CameraData *data)
 	: CameraConfiguration()
@@ -827,6 +878,8 @@  void PipelineHandlerRkISP1::stop(Camera *camera)
 
 	isp_->setFrameStartEnabled(false);
 
+	data->cancelPendingRequests();
+
 	data->ipa_->stop();
 
 	selfPath_.stop();
@@ -854,18 +907,8 @@  int PipelineHandlerRkISP1::queueRequestDevice(Camera *camera, Request *request)
 {
 	RkISP1CameraData *data = cameraData(camera);
 
-	RkISP1FrameInfo *info = data->frameInfo_.create(data, request);
-	if (!info)
-		return -ENOENT;
-
-	ipa::rkisp1::RkISP1Event ev;
-	ev.op = ipa::rkisp1::EventQueueRequest;
-	ev.frame = data->frame_;
-	ev.bufferId = info->paramBuffer->cookie();
-	ev.controls = request->controls();
-	data->ipa_->processEvent(ev);
-
-	data->frame_++;
+	data->pendingRequests_.push(request);
+	data->queuePendingRequests();
 
 	return 0;
 }
@@ -1062,6 +1105,8 @@  void PipelineHandlerRkISP1::tryCompleteRequest(Request *request)
 	data->frameInfo_.destroy(info->frame);
 
 	completeRequest(request);
+
+	data->queuePendingRequests();
 }
 
 void PipelineHandlerRkISP1::bufferReady(FrameBuffer *buffer)