| Message ID | 20251023144841.403689-10-stefan.klug@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
Hi 2025. 10. 23. 16:48 keltezéssel, Stefan Klug írta: > Use the V4L2 requests API if the dewarper supports it. > > Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com> > > --- > > Changes in v2: > - Replace strerrorname_np() by strerror() because the former is not > supported on all our targets > --- > src/libcamera/pipeline/rkisp1/rkisp1.cpp | 59 ++++++++++++++++++++++-- > 1 file changed, 56 insertions(+), 3 deletions(-) > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp > index 0e2a210e1e80..dd3907e2fb5f 100644 > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp > @@ -44,6 +44,7 @@ > #include "libcamera/internal/media_device.h" > #include "libcamera/internal/media_pipeline.h" > #include "libcamera/internal/pipeline_handler.h" > +#include "libcamera/internal/v4l2_request.h" > #include "libcamera/internal/v4l2_subdevice.h" > #include "libcamera/internal/v4l2_videodevice.h" > > @@ -210,6 +211,7 @@ private: > void imageBufferReady(FrameBuffer *buffer); > void paramBufferReady(FrameBuffer *buffer); > void statBufferReady(FrameBuffer *buffer); > + void dewarpRequestReady(V4L2Request *request); > void dewarpBufferReady(FrameBuffer *buffer); > void frameStart(uint32_t sequence); > > @@ -239,6 +241,9 @@ private: > std::vector<std::unique_ptr<FrameBuffer>> mainPathBuffers_; > std::queue<FrameBuffer *> availableMainPathBuffers_; > > + std::vector<std::unique_ptr<V4L2Request>> dewarpRequests_; > + std::queue<V4L2Request *> availableDewarpRequests_; > + > std::vector<std::unique_ptr<FrameBuffer>> paramBuffers_; > std::vector<std::unique_ptr<FrameBuffer>> statBuffers_; > std::queue<FrameBuffer *> availableParamBuffers_; > @@ -1034,6 +1039,18 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera) > > for (std::unique_ptr<FrameBuffer> &buffer : mainPathBuffers_) > availableMainPathBuffers_.push(buffer.get()); > + > + if (dewarper_->supportsRequests()) { > + ret = dewarper_->allocateRequests(kRkISP1MinBufferCount, > + &dewarpRequests_); > + if (ret < 0) > + LOG(RkISP1, Error) << "Failed to allocate requests."; > + } > + > + for (std::unique_ptr<V4L2Request> &request : dewarpRequests_) { > + request->requestDone.connect(this, &PipelineHandlerRkISP1::dewarpRequestReady); > + availableDewarpRequests_.push(request.get()); > + } I think `errorCleanup` should be updated with the following: availableDewarpRequests_.clear(); dewarpRequests_.clear(); > } > > auto pushBuffers = [&](const std::vector<std::unique_ptr<FrameBuffer>> &buffers, > @@ -1075,6 +1092,11 @@ int PipelineHandlerRkISP1::freeBuffers(Camera *camera) > statBuffers_.clear(); > mainPathBuffers_.clear(); > > + while (!availableDewarpRequests_.empty()) > + availableDewarpRequests_.pop(); `std::queue` does not have `clear()`... maybe we should use `std::dequeue` (which is the default container of `std::queue` and it has `clear()`). > + > + dewarpRequests_.clear(); > + > std::vector<unsigned int> ids; > for (IPABuffer &ipabuf : data->ipaBuffers_) > ids.push_back(ipabuf.id); > @@ -1560,6 +1582,14 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer) > return; > } > > + V4L2Request *dewarpRequest = nullptr; > + if (!dewarpRequests_.empty()) { > + /* If we have requests support, there must be one available */ > + ASSERT(!availableDewarpRequests_.empty()); > + dewarpRequest = availableDewarpRequests_.front(); > + availableDewarpRequests_.pop(); > + } > + > /* Handle scaler crop control. */ > const auto &crop = request->controls().get(controls::ScalerCrop); > if (crop) { > @@ -1597,14 +1627,37 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer) > * buffers for the dewarper are the buffers of the request, supplied > * by the application. > */ > - int ret = dewarper_->queueBuffers(buffer, request->buffers()); > - if (ret < 0) > - LOG(RkISP1, Error) << "Cannot queue buffers to dewarper: " > + int ret = dewarper_->queueBuffers(buffer, request->buffers(), dewarpRequest); > + if (ret < 0) { > + LOG(RkISP1, Error) << "Failed to queue buffers to dewarper: -" > << strerror(-ret); > > + /* Push it back into the queue. */ > + if (dewarpRequest) > + dewarpRequestReady(dewarpRequest); > + > + return; > + } > + > + if (dewarpRequest) { > + ret = dewarpRequest->queue(); > + if (ret < 0) { > + LOG(RkISP1, Error) << "Failed to queue dewarp request: -" > + << strerror(-ret); > + /* Push it back into the queue. */ > + dewarpRequestReady(dewarpRequest); > + } > + } I feel the error handling is a bit on the more complicated side, i.e. easy to miss things. But I don't have a simple idea on how it could be improved. Regards, Barnabás Pőcze > [...]
Quoting Stefan Klug (2025-10-23 23:48:10) > Use the V4L2 requests API if the dewarper supports it. > > Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com> > > --- > > Changes in v2: > - Replace strerrorname_np() by strerror() because the former is not > supported on all our targets > --- > src/libcamera/pipeline/rkisp1/rkisp1.cpp | 59 ++++++++++++++++++++++-- > 1 file changed, 56 insertions(+), 3 deletions(-) > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp > index 0e2a210e1e80..dd3907e2fb5f 100644 > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp > @@ -44,6 +44,7 @@ > #include "libcamera/internal/media_device.h" > #include "libcamera/internal/media_pipeline.h" > #include "libcamera/internal/pipeline_handler.h" > +#include "libcamera/internal/v4l2_request.h" > #include "libcamera/internal/v4l2_subdevice.h" > #include "libcamera/internal/v4l2_videodevice.h" > > @@ -210,6 +211,7 @@ private: > void imageBufferReady(FrameBuffer *buffer); > void paramBufferReady(FrameBuffer *buffer); > void statBufferReady(FrameBuffer *buffer); > + void dewarpRequestReady(V4L2Request *request); > void dewarpBufferReady(FrameBuffer *buffer); > void frameStart(uint32_t sequence); > > @@ -239,6 +241,9 @@ private: > std::vector<std::unique_ptr<FrameBuffer>> mainPathBuffers_; > std::queue<FrameBuffer *> availableMainPathBuffers_; > > + std::vector<std::unique_ptr<V4L2Request>> dewarpRequests_; > + std::queue<V4L2Request *> availableDewarpRequests_; > + > std::vector<std::unique_ptr<FrameBuffer>> paramBuffers_; > std::vector<std::unique_ptr<FrameBuffer>> statBuffers_; > std::queue<FrameBuffer *> availableParamBuffers_; > @@ -1034,6 +1039,18 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera) > > for (std::unique_ptr<FrameBuffer> &buffer : mainPathBuffers_) > availableMainPathBuffers_.push(buffer.get()); > + > + if (dewarper_->supportsRequests()) { > + ret = dewarper_->allocateRequests(kRkISP1MinBufferCount, > + &dewarpRequests_); > + if (ret < 0) > + LOG(RkISP1, Error) << "Failed to allocate requests."; > + } > + > + for (std::unique_ptr<V4L2Request> &request : dewarpRequests_) { > + request->requestDone.connect(this, &PipelineHandlerRkISP1::dewarpRequestReady); > + availableDewarpRequests_.push(request.get()); > + } > } > > auto pushBuffers = [&](const std::vector<std::unique_ptr<FrameBuffer>> &buffers, > @@ -1075,6 +1092,11 @@ int PipelineHandlerRkISP1::freeBuffers(Camera *camera) > statBuffers_.clear(); > mainPathBuffers_.clear(); > > + while (!availableDewarpRequests_.empty()) > + availableDewarpRequests_.pop(); > + > + dewarpRequests_.clear(); > + > std::vector<unsigned int> ids; > for (IPABuffer &ipabuf : data->ipaBuffers_) > ids.push_back(ipabuf.id); > @@ -1560,6 +1582,14 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer) > return; > } > > + V4L2Request *dewarpRequest = nullptr; > + if (!dewarpRequests_.empty()) { To me it feels more correct to check availableDewarpRequests_ since that's what we're dequeueing from, or supportsRequests() if you want to check capability. > + /* If we have requests support, there must be one available */ > + ASSERT(!availableDewarpRequests_.empty()); > + dewarpRequest = availableDewarpRequests_.front(); > + availableDewarpRequests_.pop(); > + } > + > /* Handle scaler crop control. */ > const auto &crop = request->controls().get(controls::ScalerCrop); > if (crop) { > @@ -1597,14 +1627,37 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer) > * buffers for the dewarper are the buffers of the request, supplied > * by the application. > */ > - int ret = dewarper_->queueBuffers(buffer, request->buffers()); > - if (ret < 0) > - LOG(RkISP1, Error) << "Cannot queue buffers to dewarper: " > + int ret = dewarper_->queueBuffers(buffer, request->buffers(), dewarpRequest); > + if (ret < 0) { > + LOG(RkISP1, Error) << "Failed to queue buffers to dewarper: -" > << strerror(-ret); > > + /* Push it back into the queue. */ > + if (dewarpRequest) > + dewarpRequestReady(dewarpRequest); > + > + return; > + } > + > + if (dewarpRequest) { > + ret = dewarpRequest->queue(); Is it possible for this to fail while queueBuffers() succeeds? Maybe ENOMEM if not EIO? Should we assert or warn? Thanks, Paul > + if (ret < 0) { > + LOG(RkISP1, Error) << "Failed to queue dewarp request: -" > + << strerror(-ret); > + /* Push it back into the queue. */ > + dewarpRequestReady(dewarpRequest); > + } > + } > + > request->metadata().set(controls::ScalerCrop, activeCrop_.value()); > } > > +void PipelineHandlerRkISP1::dewarpRequestReady(V4L2Request *request) > +{ > + request->reinit(); > + availableDewarpRequests_.push(request); > +} > + > void PipelineHandlerRkISP1::dewarpBufferReady(FrameBuffer *buffer) > { > ASSERT(activeCamera_); > -- > 2.48.1 >
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 0e2a210e1e80..dd3907e2fb5f 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -44,6 +44,7 @@ #include "libcamera/internal/media_device.h" #include "libcamera/internal/media_pipeline.h" #include "libcamera/internal/pipeline_handler.h" +#include "libcamera/internal/v4l2_request.h" #include "libcamera/internal/v4l2_subdevice.h" #include "libcamera/internal/v4l2_videodevice.h" @@ -210,6 +211,7 @@ private: void imageBufferReady(FrameBuffer *buffer); void paramBufferReady(FrameBuffer *buffer); void statBufferReady(FrameBuffer *buffer); + void dewarpRequestReady(V4L2Request *request); void dewarpBufferReady(FrameBuffer *buffer); void frameStart(uint32_t sequence); @@ -239,6 +241,9 @@ private: std::vector<std::unique_ptr<FrameBuffer>> mainPathBuffers_; std::queue<FrameBuffer *> availableMainPathBuffers_; + std::vector<std::unique_ptr<V4L2Request>> dewarpRequests_; + std::queue<V4L2Request *> availableDewarpRequests_; + std::vector<std::unique_ptr<FrameBuffer>> paramBuffers_; std::vector<std::unique_ptr<FrameBuffer>> statBuffers_; std::queue<FrameBuffer *> availableParamBuffers_; @@ -1034,6 +1039,18 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera) for (std::unique_ptr<FrameBuffer> &buffer : mainPathBuffers_) availableMainPathBuffers_.push(buffer.get()); + + if (dewarper_->supportsRequests()) { + ret = dewarper_->allocateRequests(kRkISP1MinBufferCount, + &dewarpRequests_); + if (ret < 0) + LOG(RkISP1, Error) << "Failed to allocate requests."; + } + + for (std::unique_ptr<V4L2Request> &request : dewarpRequests_) { + request->requestDone.connect(this, &PipelineHandlerRkISP1::dewarpRequestReady); + availableDewarpRequests_.push(request.get()); + } } auto pushBuffers = [&](const std::vector<std::unique_ptr<FrameBuffer>> &buffers, @@ -1075,6 +1092,11 @@ int PipelineHandlerRkISP1::freeBuffers(Camera *camera) statBuffers_.clear(); mainPathBuffers_.clear(); + while (!availableDewarpRequests_.empty()) + availableDewarpRequests_.pop(); + + dewarpRequests_.clear(); + std::vector<unsigned int> ids; for (IPABuffer &ipabuf : data->ipaBuffers_) ids.push_back(ipabuf.id); @@ -1560,6 +1582,14 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer) return; } + V4L2Request *dewarpRequest = nullptr; + if (!dewarpRequests_.empty()) { + /* If we have requests support, there must be one available */ + ASSERT(!availableDewarpRequests_.empty()); + dewarpRequest = availableDewarpRequests_.front(); + availableDewarpRequests_.pop(); + } + /* Handle scaler crop control. */ const auto &crop = request->controls().get(controls::ScalerCrop); if (crop) { @@ -1597,14 +1627,37 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer) * buffers for the dewarper are the buffers of the request, supplied * by the application. */ - int ret = dewarper_->queueBuffers(buffer, request->buffers()); - if (ret < 0) - LOG(RkISP1, Error) << "Cannot queue buffers to dewarper: " + int ret = dewarper_->queueBuffers(buffer, request->buffers(), dewarpRequest); + if (ret < 0) { + LOG(RkISP1, Error) << "Failed to queue buffers to dewarper: -" << strerror(-ret); + /* Push it back into the queue. */ + if (dewarpRequest) + dewarpRequestReady(dewarpRequest); + + return; + } + + if (dewarpRequest) { + ret = dewarpRequest->queue(); + if (ret < 0) { + LOG(RkISP1, Error) << "Failed to queue dewarp request: -" + << strerror(-ret); + /* Push it back into the queue. */ + dewarpRequestReady(dewarpRequest); + } + } + request->metadata().set(controls::ScalerCrop, activeCrop_.value()); } +void PipelineHandlerRkISP1::dewarpRequestReady(V4L2Request *request) +{ + request->reinit(); + availableDewarpRequests_.push(request); +} + void PipelineHandlerRkISP1::dewarpBufferReady(FrameBuffer *buffer) { ASSERT(activeCamera_);
Use the V4L2 requests API if the dewarper supports it. Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com> --- Changes in v2: - Replace strerrorname_np() by strerror() because the former is not supported on all our targets --- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 59 ++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-)