@@ -16,6 +16,7 @@
#include <libcamera/file_descriptor.h>
#include <libcamera/formats.h>
#include <libcamera/ipa/raspberrypi.h>
+#include <libcamera/ipa/raspberrypi_wrapper.h>
#include <libcamera/logging.h>
#include <libcamera/property_ids.h>
#include <libcamera/request.h>
@@ -35,6 +36,8 @@
#include "dma_heaps.h"
#include "staggered_ctrl.h"
+#include "libcamera/internal/ipa_proxy_raspberrypi.h"
+
namespace libcamera {
LOG_DEFINE_CATEGORY(RPI)
@@ -296,7 +299,7 @@ public:
int loadIPA();
int configureIPA();
- void queueFrameAction(unsigned int frame, const IPAOperationData &action);
+ void queueFrameAction(unsigned int frame, const RPiActionParams &action);
/* bufferComplete signal handlers. */
void unicamBufferDequeue(FrameBuffer *buffer);
@@ -307,6 +310,8 @@ public:
void handleStreamBuffer(FrameBuffer *buffer, const RPiStream *stream);
void handleState();
+ std::unique_ptr<IPAProxyRPi> ipa_;
+
CameraSensor *sensor_;
/* Array of Unicam and ISP device streams and associated buffers/streams. */
RPiDevice<Unicam, 2> unicam_;
@@ -1094,7 +1099,9 @@ void RPiCameraData::frameStarted(uint32_t sequence)
int RPiCameraData::loadIPA()
{
- ipa_ = IPAManager::createIPA(pipe_, 1, 1);
+ std::unique_ptr<IPAProxy> ptr = IPAManager::createIPA(pipe_, 1, 1);
+ ipa_ = std::unique_ptr<IPAProxyRPi>{static_cast<IPAProxyRPi*>(std::move(ptr).release())};
+
if (!ipa_)
return -ENOENT;
@@ -1110,8 +1117,8 @@ int RPiCameraData::loadIPA()
int RPiCameraData::configureIPA()
{
std::map<unsigned int, IPAStream> streamConfig;
- std::map<unsigned int, const ControlInfoMap &> entityControls;
- IPAOperationData ipaConfig = {};
+ std::map<unsigned int, const ControlInfoMap> entityControls;
+ RPiConfigureParams ipaConfig;
/* Get the device format to pass to the IPA. */
V4L2DeviceFormat sensorFormat;
@@ -1136,8 +1143,11 @@ int RPiCameraData::configureIPA()
return -ENOMEM;
/* Allow the IPA to mmap the LS table via the file descriptor. */
- ipaConfig.operation = RPI_IPA_CONFIG_LS_TABLE;
- ipaConfig.data = { static_cast<unsigned int>(lsTable_.fd()) };
+ RPiConfigurePayload payload;
+ payload.op_ = RPI_IPA_CONFIG_LS_TABLE;
+ payload.lsTableHandle_ = lsTable_;
+ payload.lsTableHandleStatic_ = lsTable_.fd();
+ ipaConfig.payload_.push_back(payload);
}
CameraSensorInfo sensorInfo = {};
@@ -1148,60 +1158,66 @@ int RPiCameraData::configureIPA()
}
/* Ready the IPA - it must know about the sensor resolution. */
- IPAOperationData result;
+ RPiConfigureParams results;
ipa_->configure(sensorInfo, streamConfig, entityControls, ipaConfig,
- &result);
+ &results);
- if (result.operation & RPI_IPA_CONFIG_STAGGERED_WRITE) {
- /*
- * Setup our staggered control writer with the sensor default
- * gain and exposure delays.
- */
- if (!staggeredCtrl_) {
- staggeredCtrl_.init(unicam_[Unicam::Image].dev(),
- { { V4L2_CID_ANALOGUE_GAIN, result.data[0] },
- { V4L2_CID_EXPOSURE, result.data[1] } });
- sensorMetadata_ = result.data[2];
- }
+ for (RPiConfigurePayload &result : results.payload_) {
+ if (result.op_ == RPI_IPA_CONFIG_STAGGERED_WRITE) {
- /* Configure the H/V flip controls based on the sensor rotation. */
- ControlList ctrls(unicam_[Unicam::Image].dev()->controls());
- int32_t rotation = sensor_->properties().get(properties::Rotation);
- ctrls.set(V4L2_CID_HFLIP, static_cast<int32_t>(!!rotation));
- ctrls.set(V4L2_CID_VFLIP, static_cast<int32_t>(!!rotation));
- unicam_[Unicam::Image].dev()->setControls(&ctrls);
- }
+ /*
+ * Setup our staggered control writer with the sensor default
+ * gain and exposure delays.
+ */
+ if (!staggeredCtrl_) {
+ staggeredCtrl_.init(unicam_[Unicam::Image].dev(),
+ { { V4L2_CID_ANALOGUE_GAIN, result.staggeredWriteResult_.gainDelay_ },
+ { V4L2_CID_EXPOSURE, result.staggeredWriteResult_.exposureDelay_ } });
+ sensorMetadata_ = result.staggeredWriteResult_.sensorMetadata_;
+ }
- if (result.operation & RPI_IPA_CONFIG_SENSOR) {
- const ControlList &ctrls = result.controls[0];
- if (!staggeredCtrl_.set(ctrls))
- LOG(RPI, Error) << "V4L2 staggered set failed";
+ /* Configure the H/V flip controls based on the sensor rotation. */
+ ControlList ctrls(unicam_[Unicam::Image].dev()->controls());
+ int32_t rotation = sensor_->properties().get(properties::Rotation);
+ ctrls.set(V4L2_CID_HFLIP, static_cast<int32_t>(!!rotation));
+ ctrls.set(V4L2_CID_VFLIP, static_cast<int32_t>(!!rotation));
+ unicam_[Unicam::Image].dev()->setControls(&ctrls);
+ }
+
+ if (result.op_ == RPI_IPA_CONFIG_SENSOR) {
+ const ControlList &ctrls = result.controls_;
+ if (!staggeredCtrl_.set(ctrls))
+ LOG(RPI, Error) << "V4L2 staggered set failed";
+ }
}
return 0;
}
void RPiCameraData::queueFrameAction([[maybe_unused]] unsigned int frame,
- const IPAOperationData &action)
+ const RPiActionParams &action)
{
/*
* The following actions can be handled when the pipeline handler is in
* a stopped state.
*/
- switch (action.operation) {
+ switch (action.op_) {
case RPI_IPA_ACTION_V4L2_SET_STAGGERED: {
- const ControlList &controls = action.controls[0];
+ const ControlList &controls = action.controls_;
if (!staggeredCtrl_.set(controls))
LOG(RPI, Error) << "V4L2 staggered set failed";
goto done;
}
case RPI_IPA_ACTION_V4L2_SET_ISP: {
- ControlList controls = action.controls[0];
+ ControlList controls = action.controls_;
isp_[Isp::Input].dev()->setControls(&controls);
goto done;
}
+
+ default:
+ break;
}
if (state_ == State::Stopped)
@@ -1211,20 +1227,20 @@ void RPiCameraData::queueFrameAction([[maybe_unused]] unsigned int frame,
* The following actions must not be handled when the pipeline handler
* is in a stopped state.
*/
- switch (action.operation) {
+ switch (action.op_) {
case RPI_IPA_ACTION_STATS_METADATA_COMPLETE: {
- unsigned int bufferId = action.data[0];
+ unsigned int bufferId = action.statsComplete_.bufferId_;
FrameBuffer *buffer = isp_[Isp::Stats].getBuffers()->at(bufferId).get();
handleStreamBuffer(buffer, &isp_[Isp::Stats]);
/* Fill the Request metadata buffer with what the IPA has provided */
- requestQueue_.front()->metadata() = std::move(action.controls[0]);
+ requestQueue_.front()->metadata() = std::move(action.statsComplete_.controls_);
state_ = State::IpaComplete;
break;
}
case RPI_IPA_ACTION_EMBEDDED_COMPLETE: {
- unsigned int bufferId = action.data[0];
+ unsigned int bufferId = action.bufferId_;
FrameBuffer *buffer = unicam_[Unicam::Embedded].getBuffers()->at(bufferId).get();
handleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);
break;
@@ -1232,20 +1248,17 @@ void RPiCameraData::queueFrameAction([[maybe_unused]] unsigned int frame,
case RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME:
case RPI_IPA_ACTION_RUN_ISP: {
- unsigned int bufferId = action.data[0];
+ unsigned int bufferId = action.bufferId_;
FrameBuffer *buffer = unicam_[Unicam::Image].getBuffers()->at(bufferId).get();
- LOG(RPI, Debug) << "Input re-queue to ISP, buffer id " << buffer->cookie()
- << ", timestamp: " << buffer->metadata().timestamp;
-
isp_[Isp::Input].dev()->queueBuffer(buffer);
- dropFrame_ = (action.operation == RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME) ? true : false;
+ dropFrame_ = (action.op_ == RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME) ? true : false;
ispOutputCount_ = 0;
break;
}
default:
- LOG(RPI, Error) << "Unknown action " << action.operation;
+ LOG(RPI, Error) << "Unknown action " << action.op_;
break;
}
@@ -1345,10 +1358,10 @@ void RPiCameraData::ispOutputDequeue(FrameBuffer *buffer)
/* If this is a stats output, hand it to the IPA now. */
if (stream == &isp_[Isp::Stats]) {
- IPAOperationData op;
- op.operation = RPI_IPA_EVENT_SIGNAL_STAT_READY;
- op.data = { RPiIpaMask::STATS | buffer->cookie() };
- ipa_->processEvent(op);
+ RPiEventParams ev;
+ ev.ev_ = RPI_IPA_EVENT_SIGNAL_STAT_READY;
+ ev.bufferId_ = { RPiIpaMask::STATS | buffer->cookie() };
+ ipa_->processEvent(ev);
}
handleState();
@@ -1491,7 +1504,7 @@ void RPiCameraData::checkRequestCompleted()
void RPiCameraData::tryRunPipeline()
{
FrameBuffer *bayerBuffer, *embeddedBuffer;
- IPAOperationData op;
+ RPiEventParams ev;
/* If any of our request or buffer queues are empty, we cannot proceed. */
if (state_ != State::Idle || requestQueue_.empty() ||
@@ -1546,9 +1559,9 @@ void RPiCameraData::tryRunPipeline()
* queue the ISP output buffer listed in the request to start the HW
* pipeline.
*/
- op.operation = RPI_IPA_EVENT_QUEUE_REQUEST;
- op.controls = { request->controls() };
- ipa_->processEvent(op);
+ ev.ev_ = RPI_IPA_EVENT_QUEUE_REQUEST;
+ ev.controls_ = { request->controls() };
+ ipa_->processEvent(ev);
/* Queue up any ISP buffers passed into the request. */
for (auto &stream : isp_) {
@@ -1567,10 +1580,10 @@ void RPiCameraData::tryRunPipeline()
<< " Bayer buffer id: " << bayerBuffer->cookie()
<< " Embedded buffer id: " << embeddedBuffer->cookie();
- op.operation = RPI_IPA_EVENT_SIGNAL_ISP_PREPARE;
- op.data = { RPiIpaMask::EMBEDDED_DATA | embeddedBuffer->cookie(),
- RPiIpaMask::BAYER_DATA | bayerBuffer->cookie() };
- ipa_->processEvent(op);
+ ev.ev_ = RPI_IPA_EVENT_SIGNAL_ISP_PREPARE;
+ ev.ispPrepare_.embeddedbufferId_ = RPiIpaMask::EMBEDDED_DATA | embeddedBuffer->cookie();
+ ev.ispPrepare_.bayerbufferId_ = RPiIpaMask::BAYER_DATA | bayerBuffer->cookie();
+ ipa_->processEvent(ev);
}
void RPiCameraData::tryFlushQueues()
This patch shows how the pipeline would use the generated IPA interface. raspberrypi_wrapper.h is included, since that contains the definitions of all the custom data structures. ipa_proxy_raspberrypi.h is also included, so that the pipeline handler can create the IPAProxyRPi. Due to the custom IPA interface, the generic IPAProxy can no longer be used. This will be elaborated on in a few patches. Other than that, the rest of the patch should be straightforward. The only changes are just fiddling the code to use the new structures. Most noteworthy is that the pipeline handler does not know nor care if it is communicating with the IPA isolated or direct. This is one of our main goals. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> --- .../pipeline/raspberrypi/raspberrypi.cpp | 125 ++++++++++-------- 1 file changed, 69 insertions(+), 56 deletions(-)