@@ -328,13 +328,11 @@ int AgcMeanLuminance::parseExposureModes(const ValueNode &tuningData)
/*
* If we don't have any exposure modes in the tuning data we create an
- * ExposureModeHelper using an empty vector of stages. This will result
- * in the ExposureModeHelper simply driving the exposure time as high as
- * possible before touching gain.
+ * ExposureModeHelper in "maximize" mode.
*/
if (exposureModeHelpers_.empty())
exposureModeHelpers_.try_emplace(controls::ExposureNormal,
- std::vector<ExposureModeHelper::Stage>{});
+ ExposureModeHelper::Maximize{});
return 0;
}
@@ -7,6 +7,7 @@
#include "exposure_mode_helper.h"
#include <algorithm>
+#include <variant>
#include <libcamera/base/log.h>
@@ -74,16 +75,55 @@ namespace ipa {
*/
/**
- * \brief Construct an ExposureModeHelper instance
+ * \class ExposureModeHelper::Maximize
+ * \brief Tag type to select mode of operation
+ *
+ * When an instance is constructed with this tag type, it will
+ * be initialized in a mode of operation where it tries to use
+ * as much exposure time as possible when reaching the target.
+ * Consequently, this mode minimizes the use of gain.
+ */
+
+/**
+ * \class ExposureModeHelper::Minimize
+ * \brief Tag type to select mode of operation
+ *
+ * When an instance is constructed with this tag type, it will
+ * be initialized in a mode of operation where it tries to use
+ * as little exposure time as possible when reaching the target.
+ * Consequently, this mode maximizes the use of gain.
+ */
+
+/**
+ * \brief Construct an ExposureModeHelper in Maximize mode
+ */
+ExposureModeHelper::ExposureModeHelper(Maximize)
+ : mode_(Maximize{})
+{
+}
+
+/**
+ * \brief Construct an ExposureModeHelper in Minimize mode
+ */
+ExposureModeHelper::ExposureModeHelper(Minimize)
+ : mode_(Minimize{})
+{
+}
+
+/**
+ * \brief Construct an ExposureModeHelper instance in staged mode
* \param[in] stages The vector of paired exposure time and gain limits
*
- * The vector of stages may be empty. In that case, the helper will simply use
- * the runtime limits set through setLimits() instead.
+ * This overload initializes the object in such a mode where it uses the
+ * stages specified in \a stages to decide how much exposure time and gain
+ * should be used to reach a given target exposure.
+ *
+ * The vector of stages must not be empty.
*/
ExposureModeHelper::ExposureModeHelper(std::vector<Stage> stages)
- : stages_(std::move(stages)), lineDuration_(1us), minExposureTime_(0us),
- maxExposureTime_(0us), minGain_(0), maxGain_(0), sensorHelper_(nullptr)
+ : mode_(std::move(stages))
{
+ ASSERT(!std::get_if<std::vector<Stage>>(&mode_)->empty());
}
/**
@@ -182,30 +222,11 @@ double ExposureModeHelper::clampGain(double gain, double *quantizationGain) cons
* \param[in] exposure Exposure value
*
* This function divides a given exposure into exposure time, analogue and
- * digital gain by iterating through stages of exposure time and gain limits.
- * At each stage the current stage's exposure time limit is multiplied by the
- * previous stage's gain limit (or 1.0 initially) to see if the combination of
- * the two can meet the required exposure. If they cannot then the current
- * stage's exposure time limit is multiplied by the same stage's gain limit to
- * see if that combination can meet the required exposure time. If they cannot
- * then the function moves to consider the next stage.
- *
- * When a combination of exposure time and gain _stage_ limits are found that
- * are sufficient to meet the required exposure, the function attempts to reduce
- * exposure time as much as possible whilst fixing gain and still meeting the
- * exposure. If a _runtime_ limit prevents exposure time from being lowered
- * enough to meet the exposure with gain fixed at the stage limit, gain is also
- * lowered to compensate.
- *
- * Once the exposure time and gain values are ascertained, gain is assigned as
- * analogue gain as much as possible, with digital gain only in use if the
- * maximum analogue gain runtime limit is unable to accommodate the exposure
- * value.
+ * digital gain according to the mode of operation configured at construction time:
*
- * If no combination of exposure time and gain limits is found that meets the
- * required exposure, then the exposure and gain of the last stage will be used,
- * unless there are no stages, in which case first the exposure, then the
- * analogue gain, then the digital gain will be maximized as necessary.
+ * - ExposureModeHelper::ExposureModeHelper(Maximize)
+ * - ExposureModeHelper::ExposureModeHelper(Maximize)
+ * - ExposureModeHelper::ExposureModeHelper(std::vector<Stage>)
*
* During the calculations the gain missed due to quantization is recorded and
* returned as quantization gain. The quantization gain is not included in the
@@ -229,8 +250,8 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const
bool exposureTimeFixed = minExposureTime_ == maxExposureTime_;
/*
- * There's no point entering the loop if we cannot change either gain
- * nor exposure time anyway.
+ * There's no point entering further processing if we can change neither
+ * gain nor exposure time anyway.
*/
if (exposureTimeFixed && gainFixed) {
exposureTime = clampExposureTime(minExposureTime_, &quantGain);
@@ -241,24 +262,78 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const
exposure / (exposureTime * gain * quantGain) };
}
- const double unitGain = clampGain(1.0);
+ return std::visit([&](const auto &mode) {
+ return splitExposure(exposure, mode);
+ }, mode_);
+}
- /*
- * If no stages are present, max out the exposure time, then the
- * analogue gain, and use digital gain for the rest.
- */
- if (stages_.empty()) {
- exposureTime = clampExposureTime(exposure / unitGain, &quantGain);
- gain = clampGain(exposure / exposureTime, &quantGain2);
- quantGain *= quantGain2;
+ExposureModeHelper::Result
+ExposureModeHelper::splitExposure(utils::Duration exposure, Maximize) const
+{
+ double quantGain, quantGain2;
- return { exposureTime, gain, quantGain,
- exposure / (exposureTime * gain * quantGain) };
- }
+ utils::Duration exposureTime = clampExposureTime(exposure / clampGain(1.0), &quantGain);
+ double gain = clampGain(exposure / exposureTime, &quantGain2);
+ quantGain *= quantGain2;
+
+ return { exposureTime, gain, quantGain,
+ exposure / (exposureTime * gain * quantGain) };
+}
+
+ExposureModeHelper::Result
+ExposureModeHelper::splitExposure(utils::Duration exposure, Minimize) const
+{
+ double quantGain, quantGain2;
+
+ double gain = clampGain(exposure / clampExposureTime(minExposureTime_), &quantGain2);
+ utils::Duration exposureTime = clampExposureTime(exposure / gain, &quantGain);
+ quantGain *= quantGain2;
+
+ return { exposureTime, gain, quantGain,
+ exposure / (exposureTime * gain * quantGain) };
+}
+
+/**
+ * \brief Split exposure into exposure time and gain
+ * \param[in] exposure Exposure value
+ * \param[in] stages The list of exposure stages
+ *
+ * This function divides a given exposure into exposure time, analogue and
+ * digital gain by iterating through stages of exposure time and gain limits.
+ * At each stage the current stage's exposure time limit is multiplied by the
+ * previous stage's gain limit (or 1.0 initially) to see if the combination of
+ * the two can meet the required exposure. If they cannot then the current
+ * stage's exposure time limit is multiplied by the same stage's gain limit to
+ * see if that combination can meet the required exposure time. If they cannot
+ * then the function moves to consider the next stage.
+ *
+ * When a combination of exposure time and gain _stage_ limits are found that
+ * are sufficient to meet the required exposure, the function attempts to reduce
+ * exposure time as much as possible whilst fixing gain and still meeting the
+ * exposure. If a _runtime_ limit prevents exposure time from being lowered
+ * enough to meet the exposure with gain fixed at the stage limit, gain is also
+ * lowered to compensate.
+ *
+ * Once the exposure time and gain values are ascertained, gain is assigned as
+ * analogue gain as much as possible, with digital gain only in use if the
+ * maximum analogue gain runtime limit is unable to accommodate the exposure
+ * value.
+ *
+ * If no combination of exposure time and gain limits is found that meets the
+ * required exposure, then the exposure and gain of the last stage will be used.
+ */
+ExposureModeHelper::Result
+ExposureModeHelper::splitExposure(utils::Duration exposure, std::span<const Stage> stages) const
+{
+ ASSERT(!stages.empty());
- double lastStageGain = unitGain;
+ utils::Duration exposureTime;
+ double gain;
+ double quantGain;
+ double quantGain2;
+ double lastStageGain = clampGain(1.0);
- for (const auto &stage : stages_) {
+ for (const auto &stage : stages) {
utils::Duration stageExposureTime = clampExposureTime(stage.exposureTime,
&quantGain);
@@ -299,8 +374,8 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const
* If no stages could satisfy the desired exposure, then use the last
* stage's exposure time and gain.
*/
- exposureTime = clampExposureTime(stages_.back().exposureTime, &quantGain);
- gain = clampGain(stages_.back().gain, &quantGain2);
+ exposureTime = clampExposureTime(stages.back().exposureTime, &quantGain);
+ gain = clampGain(stages.back().gain, &quantGain2);
quantGain *= quantGain2;
return { exposureTime, gain, quantGain,
@@ -7,6 +7,8 @@
#pragma once
+#include <span>
+#include <variant>
#include <vector>
#include <libcamera/base/utils.h>
@@ -24,7 +26,15 @@ public:
utils::Duration exposureTime;
double gain;
};
+ struct Maximize {
+ explicit Maximize() = default;
+ };
+ struct Minimize {
+ explicit Minimize() = default;
+ };
+ ExposureModeHelper(Maximize);
+ ExposureModeHelper(Minimize);
ExposureModeHelper(std::vector<Stage> stages);
void configure(utils::Duration lineLength, const CameraSensorHelper *sensorHelper);
@@ -45,14 +55,24 @@ private:
double *quantizationGain = nullptr) const;
double clampGain(double gain, double *quantizationGain = nullptr) const;
- std::vector<Stage> stages_;
-
- utils::Duration lineDuration_;
- utils::Duration minExposureTime_;
- utils::Duration maxExposureTime_;
- double minGain_;
- double maxGain_;
- const CameraSensorHelper *sensorHelper_;
+ [[nodiscard]] Result splitExposure(utils::Duration exposure,
+ Maximize) const;
+ [[nodiscard]] Result splitExposure(utils::Duration exposure,
+ Minimize) const;
+ [[nodiscard]] Result splitExposure(utils::Duration exposure,
+ std::span<const Stage> stages) const;
+
+ std::variant<
+ Maximize,
+ Minimize,
+ std::vector<Stage>
+ > mode_;
+ utils::Duration lineDuration_ = std::chrono::microseconds(1);
+ utils::Duration minExposureTime_ = {};
+ utils::Duration maxExposureTime_ = {};
+ double minGain_ = 0;
+ double maxGain_ = 0;
+ const CameraSensorHelper *sensorHelper_ = nullptr;
};
} /* namespace ipa */
Add two separate modes of operation to `ExposureModeHelper` in addition to the already existing "staged" mode. Starting with this change, the list of stages cannot be empty, and it will not default to maximizing the exposure first, then the gains. The behaviour has to be selected explicitly using one of the two new modes. The "maximize" mode is similar to the previous fallback behaviour, it maximizes exposure time as much as possible before resorting to increasing gains. The "minimize" mode is the opposite of this, it tries to keep the exposure time as low as possible, using as much gain as possible. Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> --- src/ipa/libipa/agc_mean_luminance.cpp | 6 +- src/ipa/libipa/exposure_mode_helper.cpp | 167 +++++++++++++++++------- src/ipa/libipa/exposure_mode_helper.h | 36 +++-- 3 files changed, 151 insertions(+), 58 deletions(-)