[libcamera-devel] [RFC PATCH v3 2/3] libcamera: ipu3: Try queuing pending requests if a buffer is available

Laurent Pinchart laurent.pinchart at ideasonboard.com
Tue Apr 20 04:47:40 CEST 2021


Hi Hiro,

Thank you for the patch.

On Thu, Apr 08, 2021 at 05:51:00PM +0900, Hirokazu Honda wrote:
> IPU3CameraData stores requests that have been failed due to a
> buffer shortage. The requests should be retried once enough
> buffers are available. This sets the retry function as signal to
> CIO2Device and IPU3Frame, and invokes it from
> CIO2Device::tryReturnBuffer() and IPU3Frame::remove().
> 
> Signed-off-by: Hirokazu Honda <hiroh at chromium.org>
> ---
>  src/libcamera/pipeline/ipu3/cio2.cpp   | 4 +++-
>  src/libcamera/pipeline/ipu3/cio2.h     | 3 +++
>  src/libcamera/pipeline/ipu3/frames.cpp | 6 ++++--
>  src/libcamera/pipeline/ipu3/frames.h   | 5 +++++
>  src/libcamera/pipeline/ipu3/ipu3.cpp   | 4 ++++
>  5 files changed, 19 insertions(+), 3 deletions(-)
> 
> diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
> index 3cd777d1..6490fd46 100644
> --- a/src/libcamera/pipeline/ipu3/cio2.cpp
> +++ b/src/libcamera/pipeline/ipu3/cio2.cpp
> @@ -272,7 +272,7 @@ FrameBuffer *CIO2Device::queueBuffer(Request *request, FrameBuffer *rawBuffer)
>  	/* If no buffer is provided in the request, use an internal one. */
>  	if (!buffer) {
>  		if (availableBuffers_.empty()) {
> -			LOG(IPU3, Error) << "CIO2 buffer underrun";
> +			LOG(IPU3, Debug) << "CIO2 buffer underrun";

This belongs to 1/3. Same for the two similar changes below.

>  			return nullptr;
>  		}
>  
> @@ -302,6 +302,8 @@ void CIO2Device::tryReturnBuffer(FrameBuffer *buffer)
>  			break;
>  		}
>  	}
> +
> +	bufferAvailable_.emit();
>  }
>  
>  void CIO2Device::freeBuffers()
> diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
> index 5ecc4f47..8f37ee35 100644
> --- a/src/libcamera/pipeline/ipu3/cio2.h
> +++ b/src/libcamera/pipeline/ipu3/cio2.h
> @@ -54,6 +54,7 @@ public:
>  	FrameBuffer *queueBuffer(Request *request, FrameBuffer *rawBuffer);
>  	void tryReturnBuffer(FrameBuffer *buffer);
>  	Signal<FrameBuffer *> &bufferReady() { return output_->bufferReady; }
> +	Signal<> &bufferAvailable() { return bufferAvailable_; }

You can declare the signal publicly directly, with

	Signal <> bufferAvailable;

The reason why the bufferReady() and frameStart() wrappers exist is to
proxy the signals from the signal from the csi2_ (V4L2Subdevice), but
for bufferAvailable, we create the signal directly in this class.

(On a side note, I've been thinking about making all signals private,
with public accessor functions, but it's because I'm used to the Qt
syntax ;-) So I'm not sure it would be useful, beyond the fact that it
would remove a violation of our coding style that makes all member
variable names end with _, which we don't follow for signals. If anyone
has any opinion, it's one of those bikeshedding discussions that we all
love.)

>  	Signal<uint32_t> &frameStart() { return csi2_->frameStart; }
>  
>  private:
> @@ -65,6 +66,8 @@ private:
>  	std::unique_ptr<V4L2Subdevice> csi2_;
>  	std::unique_ptr<V4L2VideoDevice> output_;
>  
> +	Signal<> bufferAvailable_;
> +
>  	std::vector<std::unique_ptr<FrameBuffer>> buffers_;
>  	std::queue<FrameBuffer *> availableBuffers_;
>  };
> diff --git a/src/libcamera/pipeline/ipu3/frames.cpp b/src/libcamera/pipeline/ipu3/frames.cpp
> index 03e8131c..58a47f98 100644
> --- a/src/libcamera/pipeline/ipu3/frames.cpp
> +++ b/src/libcamera/pipeline/ipu3/frames.cpp
> @@ -44,12 +44,12 @@ IPU3Frames::Info *IPU3Frames::create(Request *request)
>  	unsigned int id = request->sequence();
>  
>  	if (availableParamBuffers_.empty()) {
> -		LOG(IPU3, Error) << "Parameters buffer underrun";
> +		LOG(IPU3, Debug) << "Parameters buffer underrun";
>  		return nullptr;
>  	}
>  
>  	if (availableStatBuffers_.empty()) {
> -		LOG(IPU3, Error) << "Statistics buffer underrun";
> +		LOG(IPU3, Debug) << "Statistics buffer underrun";
>  		return nullptr;
>  	}
>  
> @@ -86,6 +86,8 @@ void IPU3Frames::remove(IPU3Frames::Info *info)
>  
>  	/* Delete the extended frame information. */
>  	frameInfo_.erase(info->id);
> +
> +	bufferAvailable_.emit();

I think this should be emitted in IPU3Frames::tryComplete(). You call
IPU3Frames::remove() in IPU3CameraData::queuePendingRequests() in patch
1/3, which would then emit the signal, which would call back into
IPU3CameraData::queuePendingRequests(), and that's a possible infinite
loop.

>  }
>  
>  bool IPU3Frames::tryComplete(IPU3Frames::Info *info)
> diff --git a/src/libcamera/pipeline/ipu3/frames.h b/src/libcamera/pipeline/ipu3/frames.h
> index 4acdf48e..d2e5fbb9 100644
> --- a/src/libcamera/pipeline/ipu3/frames.h
> +++ b/src/libcamera/pipeline/ipu3/frames.h
> @@ -12,6 +12,8 @@
>  #include <queue>
>  #include <vector>
>  
> +#include <libcamera/signal.h>
> +
>  namespace libcamera {
>  
>  class FrameBuffer;
> @@ -49,10 +51,13 @@ public:
>  	Info *find(unsigned int id);
>  	Info *find(FrameBuffer *buffer);
>  
> +	Signal<> &bufferAvailable() { return bufferAvailable_; }

Missing blank line.

>  private:
>  	std::queue<FrameBuffer *> availableParamBuffers_;
>  	std::queue<FrameBuffer *> availableStatBuffers_;
>  
> +	Signal<> bufferAvailable_;
> +
>  	std::map<unsigned int, std::unique_ptr<Info>> frameInfo_;
>  };
>  
> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> index c73e4f7c..462a0d9b 100644
> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> @@ -699,6 +699,8 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera)
>  	data->ipa_->mapBuffers(ipaBuffers_);
>  
>  	data->frameInfos_.init(imgu->paramBuffers_, imgu->statBuffers_);
> +	data->frameInfos_.bufferAvailable().connect(
> +		data, &IPU3CameraData::queuePendingRequests);
>  
>  	return 0;
>  }
> @@ -1123,6 +1125,8 @@ int PipelineHandlerIPU3::registerCameras()
>  		 */
>  		data->cio2_.bufferReady().connect(data.get(),
>  					&IPU3CameraData::cio2BufferReady);
> +		data->cio2_.bufferAvailable().connect(
> +			data.get(), &IPU3CameraData::queuePendingRequests);
>  		data->imgu_->input_->bufferReady.connect(&data->cio2_,
>  					&CIO2Device::tryReturnBuffer);
>  		data->imgu_->output_->bufferReady.connect(data.get(),

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list