[libcamera-devel] [PATCH v3 2/4] ipa: ipu3: ipa_context: Extend FCQueue::get()

Umang Jain umang.jain at ideasonboard.com
Sun Jun 19 22:40:22 CEST 2022


Extend the FCQueue::get() to return a IPAFrameContext for a
non-existent frame. The .get() should be able to figure out if a
existent frame context is asked for, or to create a new frame
context and return its IPAFrameContext.

We specifically want to have access to the FCQueue through the
.get() public function hence the class FCQueue needs to be now
privately inherited from std::vector<>.

Signed-off-by: Umang Jain <umang.jain at ideasonboard.com>
---
 src/ipa/ipu3/ipa_context.cpp | 97 +++++++++++++++++++++++++++++++++---
 src/ipa/ipu3/ipa_context.h   | 10 +++-
 src/ipa/ipu3/ipu3.cpp        |  6 ++-
 3 files changed, 103 insertions(+), 10 deletions(-)

diff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp
index 36d20b1b..60c58b97 100644
--- a/src/ipa/ipu3/ipa_context.cpp
+++ b/src/ipa/ipu3/ipa_context.cpp
@@ -222,15 +222,34 @@ IPAFrameContext::IPAFrameContext(uint32_t id, const ControlList &reqControls)
  * \brief A FIFO circular queue holding IPAFrameContext(s)
  *
  * FCQueue holds all the IPAFrameContext(s) related to frames required
- * to be processed by the IPA at a given point.
+ * to be processed by the IPA at a given point. An IPAFrameContext is created
+ * on the first call FCQueue::get(frame) for that frame. Subsequent calls to
+ * FCQueue::get() with the same frame number shall return the IPAFrameContext
+ * previously created until the frame is marked as complete through
+ * FCQueue::completeFrame().
+ */
+
+/**
+ * \var FCQueue::oldestFC_
+ * \brief Frame number of the oldest IPAFrameContext in the FCQueue
+ */
+
+/**
+ * \var FCQueue::latestFC_
+ * \brief Frame number of the latest IPAFrameContext in the FCQueue
+ */
+
+/**
+ * \var FCQueue::isFull_
+ * \brief Flag set when the FCQueue is full
  */
 
 /**
  * \brief FCQueue constructor
  */
 FCQueue::FCQueue()
+	: latestFC_(0), oldestFC_(0), isFull_(false)
 {
-	reset();
 }
 
 /**
@@ -238,19 +257,70 @@ FCQueue::FCQueue()
  * \param[in] frame Frame number for which the IPAFrameContext needs to
  * retrieved
  *
- * \return Pointer to the IPAFrameContext
+ * This function returns the IPAFrameContext for the desired frame. If the
+ * frame context does not exist in the queue, a new slot for the corresponding
+ * \a frame is created and returned. It is the responsibility of the caller
+ * to fill the correct IPAFrameContext parameters of newly returned
+ * IPAFrameContext.
+ *
+ * \return Pointer to the IPAFrameContext or nullptr if frame context couldn't
+ * be created
  */
 IPAFrameContext *FCQueue::get(uint32_t frame)
 {
-	IPAFrameContext &frameContext = this->at(frame % kMaxFrameContexts);
+	if (latestFC_ && frame <= latestFC_) {
+		IPAFrameContext &frameContext = this->at(frame % kMaxFrameContexts);
+		if (frame != frameContext.frame)
+			LOG(IPAIPU3, Warning)
+				<< "Got wrong frame context for frame " << frame;
+
+		return &frameContext;
+	} else {
+		if (isFull_) {
+			LOG(IPAIPU3, Warning)
+				<< "Cannot create frame context for frame " << frame
+				<< " since FCQueue is full";
+
+			return nullptr;
+		}
+
+		latestFC_ = frame;
+
+		/* Check if the queue is full to avoid over-queueing later */
+		if (oldestFC_ && latestFC_ - oldestFC_ >= kMaxFrameContexts - 1)
+			isFull_ = true;
 
-	if (frame != frameContext.frame) {
+		return &this->at(latestFC_ % kMaxFrameContexts);
+	}
+}
+
+/**
+ * \brief Notifies the FCQueue that a frame has been completed
+ * \param[in] frame The completed frame number
+ */
+void FCQueue::completeFrame(uint32_t frame)
+{
+	if (oldestFC_ != frame)
 		LOG(IPAIPU3, Warning)
-			<< "Got wrong frame context for frame" << frame
-			<< " or frame context doesn't exist yet";
+			<< "Frame " << frame << " completed out-of-sync?";
+
+	if (frame > latestFC_) {
+		LOG(IPAIPU3, Error)
+			<< "Completing a frame " << frame
+			<< " not present in the queue is disallowed";
+		return;
 	}
 
-	return &frameContext;
+	/**
+	 * \todo If there are 'gaps' in FCQueue due to frame drops, the below
+	 * oldestFC_ = frame + 1 will be be wrong.
+	 * We need to set oldestFC_ to the next valid entry, jumping the drop
+	 * gap slots.
+	 */
+	oldestFC_ = frame + 1;
+
+	if (isFull_)
+		isFull_ = false;
 }
 
 /**
@@ -262,12 +332,23 @@ void FCQueue::setSize(uint32_t size)
 	resize(size);
 }
 
+/**
+ * \fn FCQueue::isFull()
+ * \brief Checks whether the frame context queue is full
+ * \return True of FCQueue is full, False otherwise
+ */
+
 /**
  * \brief Clear the FCQueue by resetting all the entries in the ring-buffer
  */
 void FCQueue::reset()
 {
 	clear();
+
+	isFull_ = false;
+
+	latestFC_ = 0;
+	oldestFC_ = 0;
 }
 
 } /* namespace ipa::ipu3 */
diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h
index e487d34b..52a0b5e7 100644
--- a/src/ipa/ipu3/ipa_context.h
+++ b/src/ipa/ipu3/ipa_context.h
@@ -89,15 +89,23 @@ struct IPAFrameContext {
 	ControlList frameControls;
 };
 
-class FCQueue : public std::vector<IPAFrameContext>
+class FCQueue : private std::vector<IPAFrameContext>
 {
 public:
 	FCQueue();
 
+	void completeFrame(uint32_t frame);
 	void reset();
 	void setSize(uint32_t size);
 
 	IPAFrameContext *get(uint32_t frame);
+	bool isFull() { return isFull_; }
+
+private:
+	uint32_t latestFC_;
+	uint32_t oldestFC_;
+
+	bool isFull_;
 };
 
 struct IPAContext {
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index d770c254..15070fa0 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -334,6 +334,8 @@ int IPAIPU3::init(const IPASettings &settings,
  */
 int IPAIPU3::start()
 {
+	context_.frameContexts.reset();
+
 	/*
 	 * Set the sensors V4L2 controls before the first frame to ensure that
 	 * we have an expected and known configuration from the start.
@@ -605,6 +607,8 @@ void IPAIPU3::processStatsBuffer(const uint32_t frame,
 	 */
 
 	metadataReady.emit(frame, ctrls);
+
+	context_.frameContexts.completeFrame(frame);
 }
 
 /**
@@ -618,7 +622,7 @@ void IPAIPU3::processStatsBuffer(const uint32_t frame,
 void IPAIPU3::queueRequest(const uint32_t frame, const ControlList &controls)
 {
 	/* \todo Start processing for 'frame' based on 'controls'. */
-	context_.frameContexts[frame % kMaxFrameContexts] = { frame, controls };
+	*context_.frameContexts.get(frame) = { frame, controls };
 }
 
 /**
-- 
2.31.1



More information about the libcamera-devel mailing list