libcamera: ipu3: Do not unconditionally queue buffers to CIO2

Instead of unconditionally cycling buffers between the CIO2 and IMGU
pick a buffer when a request is queued to the pipeline. This is needed
if operations are to be applied to the buffer coming from CIO2 with
parameters coming from a Request.

The approach to pick a CIO2 buffer when a request is queued is similar
to other pipelines, where parameters and statistic buffers are picked
this way.

Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
Niklas Söderlund 2020-03-16 00:47:45 +01:00
parent 125be3436a
commit 5e7c5d64a6

View file

@ -8,6 +8,7 @@
#include <algorithm> #include <algorithm>
#include <iomanip> #include <iomanip>
#include <memory> #include <memory>
#include <queue>
#include <vector> #include <vector>
#include <linux/media-bus-format.h> #include <linux/media-bus-format.h>
@ -118,6 +119,9 @@ public:
int allocateBuffers(); int allocateBuffers();
void freeBuffers(); void freeBuffers();
FrameBuffer *getBuffer();
void putBuffer(FrameBuffer *buffer);
int start(); int start();
int stop(); int stop();
@ -129,6 +133,7 @@ public:
private: private:
std::vector<std::unique_ptr<FrameBuffer>> buffers_; std::vector<std::unique_ptr<FrameBuffer>> buffers_;
std::queue<FrameBuffer *> availableBuffers_;
}; };
class IPU3Stream : public Stream class IPU3Stream : public Stream
@ -716,11 +721,21 @@ void PipelineHandlerIPU3::stop(Camera *camera)
int PipelineHandlerIPU3::queueRequestDevice(Camera *camera, Request *request) int PipelineHandlerIPU3::queueRequestDevice(Camera *camera, Request *request)
{ {
IPU3CameraData *data = cameraData(camera);
FrameBuffer *buffer;
int error = 0; int error = 0;
/* Get a CIO2 buffer, associate it with the request and queue it. */
buffer = data->cio2_.getBuffer();
if (!buffer)
return -EINVAL;
buffer->setRequest(request);
data->cio2_.output_->queueBuffer(buffer);
for (auto it : request->buffers()) { for (auto it : request->buffers()) {
IPU3Stream *stream = static_cast<IPU3Stream *>(it.first); IPU3Stream *stream = static_cast<IPU3Stream *>(it.first);
FrameBuffer *buffer = it.second; buffer = it.second;
int ret = stream->device_->dev->queueBuffer(buffer); int ret = stream->device_->dev->queueBuffer(buffer);
if (ret < 0) if (ret < 0)
@ -892,7 +907,7 @@ void IPU3CameraData::imguInputBufferReady(FrameBuffer *buffer)
if (buffer->metadata().status == FrameMetadata::FrameCancelled) if (buffer->metadata().status == FrameMetadata::FrameCancelled)
return; return;
cio2_.output_->queueBuffer(buffer); cio2_.putBuffer(buffer);
} }
/** /**
@ -1416,29 +1431,45 @@ int CIO2Device::allocateBuffers()
{ {
int ret = output_->allocateBuffers(CIO2_BUFFER_COUNT, &buffers_); int ret = output_->allocateBuffers(CIO2_BUFFER_COUNT, &buffers_);
if (ret < 0) if (ret < 0)
LOG(IPU3, Error) << "Failed to allocate CIO2 buffers"; return ret;
for (std::unique_ptr<FrameBuffer> &buffer : buffers_)
availableBuffers_.push(buffer.get());
return ret; return ret;
} }
void CIO2Device::freeBuffers() void CIO2Device::freeBuffers()
{ {
availableBuffers_ = {};
buffers_.clear(); buffers_.clear();
if (output_->releaseBuffers()) if (output_->releaseBuffers())
LOG(IPU3, Error) << "Failed to release CIO2 buffers"; LOG(IPU3, Error) << "Failed to release CIO2 buffers";
} }
int CIO2Device::start() FrameBuffer *CIO2Device::getBuffer()
{ {
for (const std::unique_ptr<FrameBuffer> &buffer : buffers_) { if (availableBuffers_.empty()) {
int ret = output_->queueBuffer(buffer.get()); LOG(IPU3, Error) << "CIO2 buffer underrun";
if (ret) { return nullptr;
LOG(IPU3, Error) << "Failed to queue CIO2 buffer";
return ret;
}
} }
FrameBuffer *buffer = availableBuffers_.front();
availableBuffers_.pop();
return buffer;
}
void CIO2Device::putBuffer(FrameBuffer *buffer)
{
availableBuffers_.push(buffer);
}
int CIO2Device::start()
{
return output_->streamOn(); return output_->streamOn();
} }