summaryrefslogtreecommitdiff
path: root/src/ipa/libipa/fc_queue.h
blob: a1d13652110723443728d34487368a9436c4dcaa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* 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 */