Some IPA modules, like the RkISP1 one, call FCQueue::get(0) at IPA::start() time, before any frame context has been allocated with FCQueue::alloc() called at queueRequest() time. The FCQueue implementation aims to detect when a FrameContext is get() before it is alloc()-ated, Warns about it, and initializes the FrameContext before returning it. In case of frame#0, a get() preceding an alloc() call is not detected as the "frame == frameContext.frame" test returns success, as FrameContexts are zeroed by default. As a result, the first returned FrameContext is not initialized. Explicitly test for frame#0 to make sure the FrameContext is initialized if get(0) is called before alloc(0). To avoid re-initializing a frame context, in case alloc() has been called correctly before get(), introduce an "initialised" state variable that tracks the FrameContext initialisation state. Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>
138 lines
3.3 KiB
C++
138 lines
3.3 KiB
C++
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
/*
|
|
* Copyright (C) 2022, Google Inc.
|
|
*
|
|
* IPA Frame context queue
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <vector>
|
|
|
|
#include <libcamera/base/log.h>
|
|
|
|
namespace libcamera {
|
|
|
|
LOG_DECLARE_CATEGORY(FCQueue)
|
|
|
|
namespace ipa {
|
|
|
|
template<typename FrameContext>
|
|
class FCQueue;
|
|
|
|
struct FrameContext {
|
|
private:
|
|
template<typename T> friend class FCQueue;
|
|
uint32_t frame;
|
|
bool initialised = false;
|
|
};
|
|
|
|
template<typename FrameContext>
|
|
class FCQueue
|
|
{
|
|
public:
|
|
FCQueue(unsigned int size)
|
|
: contexts_(size)
|
|
{
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
for (FrameContext &ctx : contexts_) {
|
|
ctx.initialised = false;
|
|
ctx.frame = 0;
|
|
}
|
|
}
|
|
|
|
FrameContext &alloc(const uint32_t frame)
|
|
{
|
|
FrameContext &frameContext = contexts_[frame % contexts_.size()];
|
|
|
|
/*
|
|
* Do not re-initialise if a get() call has already fetched this
|
|
* frame context to preseve the context.
|
|
*
|
|
* \todo If the the sequence number of the context to initialise
|
|
* is smaller than the sequence number of the queue slot to use,
|
|
* it means that we had a serious request underrun and more
|
|
* frames than the queue size has been produced since the last
|
|
* time the application has queued a request. Does this deserve
|
|
* an error condition ?
|
|
*/
|
|
if (frame != 0 && frame <= frameContext.frame)
|
|
LOG(FCQueue, Warning)
|
|
<< "Frame " << frame << " already initialised";
|
|
else
|
|
init(frameContext, frame);
|
|
|
|
return frameContext;
|
|
}
|
|
|
|
FrameContext &get(uint32_t frame)
|
|
{
|
|
FrameContext &frameContext = contexts_[frame % contexts_.size()];
|
|
|
|
/*
|
|
* If the IPA algorithms try to access a frame context slot which
|
|
* has been already overwritten by a newer context, it means the
|
|
* frame context queue has overflowed and the desired context
|
|
* has been forever lost. The pipeline handler shall avoid
|
|
* queueing more requests to the IPA than the frame context
|
|
* queue size.
|
|
*/
|
|
if (frame < frameContext.frame)
|
|
LOG(FCQueue, Fatal) << "Frame context for " << frame
|
|
<< " has been overwritten by "
|
|
<< frameContext.frame;
|
|
|
|
if (frame == 0 && !frameContext.initialised) {
|
|
/*
|
|
* If the IPA calls get() at start() time it will get an
|
|
* un-intialized FrameContext as the below "frame ==
|
|
* frameContext.frame" check will return success because
|
|
* FrameContexts are zeroed at creation time.
|
|
*
|
|
* Make sure the FrameContext gets initialised if get()
|
|
* is called before alloc() by the IPA for frame#0.
|
|
*/
|
|
init(frameContext, frame);
|
|
|
|
return frameContext;
|
|
}
|
|
|
|
if (frame == frameContext.frame)
|
|
return frameContext;
|
|
|
|
/*
|
|
* The frame context has been retrieved before it was
|
|
* initialised through the initialise() call. This indicates an
|
|
* algorithm attempted to access a Frame context before it was
|
|
* queued to the IPA. Controls applied for this request may be
|
|
* left unhandled.
|
|
*
|
|
* \todo Set an error flag for per-frame control errors.
|
|
*/
|
|
LOG(FCQueue, Warning)
|
|
<< "Obtained an uninitialised FrameContext for " << frame;
|
|
|
|
init(frameContext, frame);
|
|
|
|
return frameContext;
|
|
}
|
|
|
|
private:
|
|
void init(FrameContext &frameContext, const uint32_t frame)
|
|
{
|
|
frameContext = {};
|
|
frameContext.frame = frame;
|
|
frameContext.initialised = true;
|
|
}
|
|
|
|
std::vector<FrameContext> contexts_;
|
|
};
|
|
|
|
} /* namespace ipa */
|
|
|
|
} /* namespace libcamera */
|