@@ -39,6 +39,7 @@ class PipelineHandler : public std::enable_shared_from_this<PipelineHandler>,
public:
struct Options {
unsigned int maxQueuedRequestsDevice = 32;
+ bool usesBufferPool = false;
};
PipelineHandler(CameraManager *manager, const Options &options);
@@ -110,9 +111,12 @@ private:
void mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media);
virtual void disconnect();
+ [[nodiscard]] bool prepareRequest(Request *request);
void doQueueRequest(Request *request);
void doQueueRequests(Camera *camera);
+ void buffersAdded(Camera *camera);
+
std::vector<std::shared_ptr<MediaDevice>> mediaDevices_;
std::vector<std::weak_ptr<Camera>> cameras_;
@@ -29,6 +29,8 @@ public:
Camera *camera() const { return camera_; }
bool hasPendingBuffers() const { return pending_ > 0; }
+ [[nodiscard]] Request::BufferMap &buffers() { return LIBCAMERA_O_PTR()->bufferMap_; } // \todo fixme suboptimal
+
ControlList &metadata() { return metadata_; }
bool completeBuffer(FrameBuffer *buffer);
@@ -78,6 +78,16 @@ LOG_DEFINE_CATEGORY(Pipeline)
* queue, to be queued at a later stage.
*/
+/**
+ * \var PipelineHandler::Options::usesBufferPool
+ * \brief Whether or not the pipeline handler uses the camera's buffer pool
+ *
+ * If this option is set to \a false, then the pipeline handler base class
+ * will ensure that the requests have the necessary buffers when queueRequestDevice()
+ * is called. Otherwise it is the responsibility of the derived class to
+ * manage the buffers.
+ */
+
/**
* \brief Construct a PipelineHandler instance
* \param[in] manager The camera manager
@@ -493,6 +503,38 @@ void PipelineHandler::queueRequest(Request *request)
doQueueRequests(camera);
}
+bool PipelineHandler::prepareRequest(Request *request)
+{
+ if (!options_.usesBufferPool) {
+ Camera *camera = request->_d()->camera();
+ Camera::Private *data = camera->_d();
+ auto &buffers = request->_d()->buffers();
+
+ ASSERT(request->_d()->pending_ == buffers.size());
+
+ for (auto &[stream, buffer] : buffers) {
+ auto it = data->streamData_.find(stream);
+ ASSERT(it != data->streamData_.end());
+ ASSERT(it->second.active);
+
+ if (buffer)
+ continue;
+
+ auto &pool = it->second.buffers;
+ if (pool.empty())
+ return false;
+
+ buffer = pool.back();
+ pool.pop_back();
+
+ buffer->_d()->setRequest(request);
+ buffer->_d()->stream_ = stream;
+ }
+ }
+
+ return true;
+}
+
/**
* \brief Queue one requests to the device
*/
@@ -514,6 +556,9 @@ void PipelineHandler::doQueueRequest(Request *request)
int ret = queueRequestDevice(camera, request);
if (ret)
cancelRequest(request);
+ // \todo what to do with buffers from pool? probably nothing?
+ // let's say it's the applications responsibility to process
+ // *all* buffers in *all* completed requests
}
/**
@@ -530,6 +575,8 @@ void PipelineHandler::doQueueRequests(Camera *camera)
break;
Request *request = data->waitingRequests_.front();
+ if (!prepareRequest(request))
+ break;
/*
* Pop the request first, in case doQueueRequests() is called
@@ -625,6 +672,12 @@ void PipelineHandler::cancelRequest(Request *request)
completeRequest(request);
}
+void PipelineHandler::buffersAdded(Camera *camera)
+{
+ if (!options_.usesBufferPool)
+ doQueueRequests(camera);
+}
+
/**
* \fn PipelineHandler::addBuffer()
* \brief Add buffers to the buffer pool of the camera
@@ -679,18 +732,24 @@ void PipelineHandler::addBuffer(Camera *camera,
<< "Waiting on fence:" << buffer->_d()->fence()->fd().get()
<< " for stream:" << stream << " buffer:" << buffer;
- it2->notifier.activated.connect(this, [=] {
+ it2->notifier.activated.connect(this, [=, this] {
LOG(Pipeline, Debug)
<< "Activated fence:" << it2->buffer->_d()->fence()->fd().get()
<< " for stream:" << it2->stream << " buffer:" << it2->buffer;
+ PipelineHandler *self = this;
+ Camera *cam = camera;
+
std::ignore = it2->buffer->releaseFence();
it->second.buffers.push_back(it2->buffer);
d->pendingFences_.erase(it2);
/* Lambda is now destroy, no captured variable should be accessed. */
+
+ self->buffersAdded(cam);
});
} else {
it->second.buffers.push_back(buffer);
+ buffersAdded(camera);
}
}
@@ -79,6 +79,11 @@ Request::Private::~Private()
* otherwise
*/
+/**
+ * \fn Request::Private::buffers()
+ * \copydoc Request::buffers()
+ */
+
/**
* \fn Request::Private::metadata()
* \brief Retrieve the request's metadata
If the pipeline handler itself is not using the camera's buffer pool, then ensure that each stream of the request has a buffer by retrieving buffers before `queueRequestDevice()`. Additionally, try to queue the waiting requests if a buffer has been added to the pool. Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> --- include/libcamera/internal/pipeline_handler.h | 4 ++ include/libcamera/internal/request.h | 2 + src/libcamera/pipeline_handler.cpp | 61 ++++++++++++++++++- src/libcamera/request.cpp | 5 ++ 4 files changed, 71 insertions(+), 1 deletion(-)