summaryrefslogtreecommitdiff
path: root/test/v4l2_videodevice/request_buffers.cpp
blob: fb577147eff88883df93a4839780e1d538b040b2 (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
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * libcamera V4L2 API tests
 */

#include "v4l2_videodevice_test.h"

class RequestBuffersTest : public V4L2VideoDeviceTest
{
public:
	RequestBuffersTest()
		: V4L2VideoDeviceTest("vimc", "Raw Capture 0") {}

protected:
	int run()
	{
		const unsigned int bufferCount = 8;

		int ret = capture_->allocateBuffers(bufferCount, &buffers_);
		if (ret != bufferCount)
			return TestFail;

		return TestPass;
	}
};

TEST_REGISTER(RequestBuffersTest)
08 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 */