Skip to content

Commit 3b774c9

Browse files
committed
pipeline: rpi: Report which control lists apply to each request
This forms part of Raspberry Pi's implementation of "per frame control". Control lists that are queued to the pipeline handler through Camera::queueControls are assigned a sequence number and get applied to the next possible request. They are tracked through the pipeline using "delayed contexts". Finally, the control list sequence number that is applied to the request is reported back through the "ControlListSequence" metadata. Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
1 parent 2de33b4 commit 3b774c9

File tree

5 files changed

+118
-10
lines changed

5 files changed

+118
-10
lines changed

src/ipa/rpi/common/ipa_base.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,9 @@ void IpaBase::prepareIsp(const PrepareParams &params)
440440
fillDeviceStatus(params.sensorControls, ipaContext);
441441
fillSyncParams(params, ipaContext);
442442

443+
if (!params.requestControls.empty())
444+
rpiMetadata.set("ipa.request_controls", true);
445+
443446
if (params.buffers.embedded) {
444447
/*
445448
* Pipeline handler has supplied us with an embedded data buffer,
@@ -460,7 +463,7 @@ void IpaBase::prepareIsp(const PrepareParams &params)
460463
*/
461464
AgcStatus agcStatus;
462465
bool hdrChange = false;
463-
RPiController::Metadata &delayedMetadata = rpiMetadata_[params.delayContext];
466+
RPiController::Metadata &delayedMetadata = rpiMetadata_[params.delayContext % rpiMetadata_.size()];
464467
if (!delayedMetadata.get<AgcStatus>("agc.status", agcStatus)) {
465468
rpiMetadata.set("agc.delayed_status", agcStatus);
466469
hdrChange = agcStatus.hdr.mode != hdrStatus_.mode;
@@ -473,9 +476,13 @@ void IpaBase::prepareIsp(const PrepareParams &params)
473476
*/
474477
helper_->prepare(embeddedBuffer, rpiMetadata);
475478

479+
bool delayedRequestControls = false;
480+
delayedMetadata.get<bool>("ipa.request_controls", delayedRequestControls);
481+
476482
/* Allow a 10% margin on the comparison below. */
477483
Duration delta = (frameTimestamp - lastRunTimestamp_) * 1.0ns;
478-
if (lastRunTimestamp_ && frameCount_ > invalidCount_ &&
484+
if (!delayedRequestControls && params.requestControls.empty() &&
485+
lastRunTimestamp_ && frameCount_ > invalidCount_ &&
479486
delta < controllerMinFrameDuration * 0.9 && !hdrChange) {
480487
/*
481488
* Ensure we merge the previous frame's metadata with the current
@@ -558,7 +565,7 @@ void IpaBase::processStats(const ProcessParams &params)
558565
ControlList ctrls(sensorCtrls_);
559566
applyAGC(&agcStatus, ctrls, offset);
560567
rpiMetadata.set("agc.status", agcStatus);
561-
setDelayedControls.emit(ctrls, ipaContext);
568+
setDelayedControls.emit(ctrls, params.ipaContext);
562569
setCameraTimeoutValue();
563570
}
564571

@@ -975,8 +982,6 @@ void IpaBase::applyControls(const ControlList &controls)
975982

976983
/* The control provides units of microseconds. */
977984
agc->setFixedExposureTime(0, ctrl.second.get<int32_t>() * 1.0us);
978-
979-
libcameraMetadata_.set(controls::ExposureTime, ctrl.second.get<int32_t>());
980985
break;
981986
}
982987

@@ -1000,9 +1005,6 @@ void IpaBase::applyControls(const ControlList &controls)
10001005
break;
10011006

10021007
agc->setFixedGain(0, ctrl.second.get<float>());
1003-
1004-
libcameraMetadata_.set(controls::AnalogueGain,
1005-
ctrl.second.get<float>());
10061008
break;
10071009
}
10081010

src/libcamera/pipeline/rpi/common/pipeline_base.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,4 +1531,88 @@ void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request
15311531
}
15321532
}
15331533

1534+
static bool isControlDelayed(unsigned int id)
1535+
{
1536+
return id == controls::ExposureTime ||
1537+
id == controls::AnalogueGain ||
1538+
id == controls::FrameDurationLimits ||
1539+
id == controls::AeEnable ||
1540+
id == controls::ExposureTimeMode ||
1541+
id == controls::AnalogueGainMode;
1542+
}
1543+
1544+
void CameraData::handleControlLists(uint32_t delayContext)
1545+
{
1546+
/*
1547+
* If any control lists have been queued for us, merge them into the
1548+
* next request that we're going to process. This route saves controls
1549+
* from being queued always with the last request, meaning they get
1550+
* picked up here more quickly.
1551+
*/
1552+
Request *request = requestQueue_.front();
1553+
if (!controlsQueue_.empty()) {
1554+
request->controls().merge(std::move(controlsQueue_.front()),
1555+
ControlList::MergePolicy::OverwriteExisting);
1556+
controlsQueue_.pop();
1557+
controlListId_++;
1558+
LOG(RPI, Debug) << "Popped control list " << controlListId_ << " from queue";
1559+
}
1560+
1561+
/*
1562+
* Record which control list corresponds to this ipaCookie. Because setDelayedControls
1563+
* now gets called by the IPA from the start of the following frame, we must record
1564+
* the previous control list id.
1565+
*/
1566+
syncTable_.emplace(SyncTableEntry{ request->sequence(), controlListId_ });
1567+
LOG(RPI, Debug) << "Add sync table entry: sequence " << request->sequence()
1568+
<< " control list id " << controlListId_;
1569+
1570+
/*
1571+
* We know we that we added an entry for every delayContext, so we can
1572+
* find the one for this Bayer frame, and this links us to the correct
1573+
* control list. Anything ahead of "our" entry in the queue is old, so
1574+
* can be dropped.
1575+
*/
1576+
while (!syncTable_.empty() &&
1577+
syncTable_.front().ipaCookie != delayContext) {
1578+
LOG(RPI, Debug) << "Pop sync entry: ipa cookie "
1579+
<< syncTable_.front().ipaCookie << " control id "
1580+
<< syncTable_.front().controlListId << " for job "
1581+
<< delayContext;
1582+
syncTable_.pop();
1583+
}
1584+
1585+
if (syncTable_.empty())
1586+
LOG(RPI, Warning) << "Unable to find ipa cookie for PFC";
1587+
else {
1588+
LOG(RPI, Debug) << "Using sync control id " << syncTable_.front().controlListId;
1589+
requestControlId_ = syncTable_.front().controlListId;
1590+
}
1591+
1592+
/* The control list id is reported as the "ControlListSequence" in the metadata. */
1593+
request->_d()->metadata().set(controls::rpi::ControlListSequence, requestControlId_);
1594+
1595+
/*
1596+
* Controls that take effect immediately (typically ISP controls) have to be
1597+
* delayed so as to synchronise with those controls that do get delayed. So we
1598+
* must remove them from the current request, and push them onto a queue so
1599+
* that they can be used later.
1600+
*/
1601+
ControlList controls = std::move(request->controls());
1602+
immediateControls_.push({ controlListId_, request->controls() });
1603+
for (const auto &ctrl : controls) {
1604+
if (isControlDelayed(ctrl.first))
1605+
request->controls().set(ctrl.first, ctrl.second);
1606+
else
1607+
immediateControls_.back().controls.set(ctrl.first, ctrl.second);
1608+
}
1609+
/* "Immediate" controls that have become due are now merged back into this request. */
1610+
while (!immediateControls_.empty() &&
1611+
immediateControls_.front().controlListId <= requestControlId_) {
1612+
request->controls().merge(immediateControls_.front().controls,
1613+
ControlList::MergePolicy::OverwriteExisting);
1614+
immediateControls_.pop();
1615+
}
1616+
}
1617+
15341618
} /* namespace libcamera */

src/libcamera/pipeline/rpi/common/pipeline_base.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class CameraData : public Camera::Private
4848
{
4949
public:
5050
CameraData(PipelineHandler *pipe)
51-
: Camera::Private(pipe), state_(State::Stopped),
51+
: Camera::Private(pipe), state_(State::Stopped), controlListId_(0),
5252
startupFrameCount_(0), invalidFrameCount_(0), buffersAllocated_(false)
5353
{
5454
}
@@ -131,6 +131,8 @@ class CameraData : public Camera::Private
131131

132132
std::queue<Request *> requestQueue_;
133133
std::queue<ControlList> controlsQueue_;
134+
uint64_t controlListId_;
135+
uint64_t requestControlId_;
134136

135137
/* For handling digital zoom. */
136138
IPACameraSensorInfo sensorInfo_;
@@ -176,10 +178,24 @@ class CameraData : public Camera::Private
176178

177179
ClockRecovery wallClockRecovery_;
178180

181+
struct SyncTableEntry {
182+
uint32_t ipaCookie;
183+
uint64_t controlListId;
184+
};
185+
std::queue<SyncTableEntry> syncTable_;
186+
187+
struct ImmediateControlsEntry {
188+
uint64_t controlListId;
189+
ControlList controls;
190+
};
191+
std::queue<ImmediateControlsEntry> immediateControls_;
192+
179193
protected:
180194
void fillRequestMetadata(const ControlList &bufferControls,
181195
Request *request);
182196

197+
void handleControlLists(uint32_t delayContext);
198+
183199
virtual void tryRunPipeline() = 0;
184200

185201
private:

src/libcamera/pipeline/rpi/pisp/pisp.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2311,6 +2311,9 @@ void PiSPCameraData::tryRunPipeline()
23112311

23122312
fillRequestMetadata(job.sensorControls, request);
23132313

2314+
/* This sorts out synchronisation with the ControlList queue. */
2315+
handleControlLists(job.delayContext);
2316+
23142317
/* Set our state to say the pipeline is active. */
23152318
state_ = State::Busy;
23162319

@@ -2327,7 +2330,7 @@ void PiSPCameraData::tryRunPipeline()
23272330
params.buffers.bayer = RPi::MaskBayerData | bayerId;
23282331
params.buffers.stats = RPi::MaskStats | statsId;
23292332
params.buffers.embedded = 0;
2330-
params.ipaContext = requestQueue_.front()->sequence();
2333+
params.ipaContext = request->sequence();
23312334
params.delayContext = job.delayContext;
23322335
params.sensorControls = std::move(job.sensorControls);
23332336
params.requestControls = request->controls();

src/libcamera/pipeline/rpi/vc4/vc4.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,9 @@ void Vc4CameraData::tryRunPipeline()
984984

985985
fillRequestMetadata(bayerFrame.controls, request);
986986

987+
/* This sorts out synchronisation with the ControlList queue. */
988+
handleControlLists(bayerFrame.delayContext);
989+
987990
/* Set our state to say the pipeline is active. */
988991
state_ = State::Busy;
989992

0 commit comments

Comments
 (0)