diff options
Diffstat (limited to 'test/ipa')
-rw-r--r-- | test/ipa/ipa_interface_test.cpp | 109 | ||||
-rw-r--r-- | test/ipa/ipa_module_test.cpp | 9 | ||||
-rw-r--r-- | test/ipa/ipa_wrappers_test.cpp | 394 | ||||
-rw-r--r-- | test/ipa/libipa/fixedpoint.cpp | 108 | ||||
-rw-r--r-- | test/ipa/libipa/interpolator.cpp | 54 | ||||
-rw-r--r-- | test/ipa/libipa/meson.build | 18 | ||||
-rw-r--r-- | test/ipa/libipa/vector.cpp | 100 | ||||
-rw-r--r-- | test/ipa/meson.build | 21 |
8 files changed, 371 insertions, 442 deletions
diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp index cafc249b..b8178366 100644 --- a/test/ipa/ipa_interface_test.cpp +++ b/test/ipa/ipa_interface_test.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2019, Google Inc. * - * ipa_interface_test.cpp - Test the IPA interface + * Test the IPA interface */ #include <fcntl.h> @@ -12,44 +12,52 @@ #include <sys/types.h> #include <unistd.h> -#include <libcamera/event_dispatcher.h> -#include <libcamera/event_notifier.h> -#include <libcamera/timer.h> +#include <libcamera/ipa/vimc_ipa_proxy.h> -#include <ipa/ipa_vimc.h> +#include <libcamera/base/event_dispatcher.h> +#include <libcamera/base/event_notifier.h> +#include <libcamera/base/object.h> +#include <libcamera/base/thread.h> +#include <libcamera/base/timer.h> + +#include "libcamera/internal/camera_manager.h" +#include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/ipa_manager.h" +#include "libcamera/internal/ipa_module.h" +#include "libcamera/internal/pipeline_handler.h" -#include "device_enumerator.h" -#include "ipa_manager.h" -#include "ipa_module.h" -#include "pipeline_handler.h" #include "test.h" -#include "thread.h" -using namespace std; using namespace libcamera; +using namespace std; +using namespace std::chrono_literals; class IPAInterfaceTest : public Test, public Object { public: IPAInterfaceTest() - : trace_(IPAOperationNone), notifier_(nullptr), fd_(-1) + : trace_(ipa::vimc::IPAOperationNone), notifier_(nullptr), fd_(-1) { } ~IPAInterfaceTest() { delete notifier_; + ipa_.reset(); + cameraManager_.reset(); } protected: int init() override { + cameraManager_ = make_unique<CameraManager>(); + /* Create a pipeline handler for vimc. */ - std::vector<PipelineHandlerFactory *> &factories = - PipelineHandlerFactory::factories(); - for (PipelineHandlerFactory *factory : factories) { - if (factory->name() == "PipelineHandlerVimc") { - pipe_ = factory->create(nullptr); + const std::vector<PipelineHandlerFactoryBase *> &factories = + PipelineHandlerFactoryBase::factories(); + for (const PipelineHandlerFactoryBase *factory : factories) { + if (factory->name() == "vimc") { + pipe_ = factory->create(cameraManager_.get()); break; } } @@ -60,22 +68,22 @@ protected: } /* Create and open the communication FIFO. */ - int ret = mkfifo(VIMC_IPA_FIFO_PATH, S_IRUSR | S_IWUSR); + int ret = mkfifo(ipa::vimc::VimcIPAFIFOPath.c_str(), S_IRUSR | S_IWUSR); if (ret) { ret = errno; cerr << "Failed to create IPA test FIFO at '" - << VIMC_IPA_FIFO_PATH << "': " << strerror(ret) + << ipa::vimc::VimcIPAFIFOPath << "': " << strerror(ret) << endl; return TestFail; } - ret = open(VIMC_IPA_FIFO_PATH, O_RDONLY | O_NONBLOCK); + ret = open(ipa::vimc::VimcIPAFIFOPath.c_str(), O_RDONLY | O_NONBLOCK); if (ret < 0) { ret = errno; cerr << "Failed to open IPA test FIFO at '" - << VIMC_IPA_FIFO_PATH << "': " << strerror(ret) + << ipa::vimc::VimcIPAFIFOPath << "': " << strerror(ret) << endl; - unlink(VIMC_IPA_FIFO_PATH); + unlink(ipa::vimc::VimcIPAFIFOPath.c_str()); return TestFail; } fd_ = ret; @@ -91,49 +99,82 @@ protected: EventDispatcher *dispatcher = thread()->eventDispatcher(); Timer timer; - ipa_ = IPAManager::instance()->createIPA(pipe_.get(), 0, 0); + ipa_ = IPAManager::createIPA<ipa::vimc::IPAProxyVimc>(pipe_.get(), 0, 0); if (!ipa_) { cerr << "Failed to create VIMC IPA interface" << endl; return TestFail; } /* Test initialization of IPA module. */ - ipa_->init(); - timer.start(1000); - while (timer.isRunning() && trace_ != IPAOperationInit) + std::string conf = ipa_->configurationFile("vimc.conf"); + Flags<ipa::vimc::TestFlag> inFlags; + Flags<ipa::vimc::TestFlag> outFlags; + int ret = ipa_->init(IPASettings{ conf, "vimc" }, + ipa::vimc::IPAOperationInit, + inFlags, &outFlags); + if (ret < 0) { + cerr << "IPA interface init() failed" << endl; + return TestFail; + } + + timer.start(1000ms); + while (timer.isRunning() && trace_ != ipa::vimc::IPAOperationInit) dispatcher->processEvents(); - if (trace_ != IPAOperationInit) { + if (trace_ != ipa::vimc::IPAOperationInit) { cerr << "Failed to test IPA initialization sequence" << endl; return TestFail; } + /* Test start of IPA module. */ + ipa_->start(); + timer.start(1000ms); + while (timer.isRunning() && trace_ != ipa::vimc::IPAOperationStart) + dispatcher->processEvents(); + + if (trace_ != ipa::vimc::IPAOperationStart) { + cerr << "Failed to test IPA start sequence" << endl; + return TestFail; + } + + /* Test stop of IPA module. */ + ipa_->stop(); + timer.start(1000ms); + while (timer.isRunning() && trace_ != ipa::vimc::IPAOperationStop) + dispatcher->processEvents(); + + if (trace_ != ipa::vimc::IPAOperationStop) { + cerr << "Failed to test IPA stop sequence" << endl; + return TestFail; + } + return TestPass; } void cleanup() override { close(fd_); - unlink(VIMC_IPA_FIFO_PATH); + unlink(ipa::vimc::VimcIPAFIFOPath.c_str()); } private: - void readTrace(EventNotifier *notifier) + void readTrace() { - ssize_t s = read(notifier->fd(), &trace_, sizeof(trace_)); + ssize_t s = read(notifier_->fd(), &trace_, sizeof(trace_)); if (s < 0) { int ret = errno; cerr << "Failed to read from IPA test FIFO at '" - << VIMC_IPA_FIFO_PATH << "': " << strerror(ret) + << ipa::vimc::VimcIPAFIFOPath << "': " << strerror(ret) << endl; - trace_ = IPAOperationNone; + trace_ = ipa::vimc::IPAOperationNone; } } std::shared_ptr<PipelineHandler> pipe_; - std::unique_ptr<IPAInterface> ipa_; - enum IPAOperationCode trace_; + std::unique_ptr<ipa::vimc::IPAProxyVimc> ipa_; + std::unique_ptr<CameraManager> cameraManager_; + enum ipa::vimc::IPAOperationCode trace_; EventNotifier *notifier_; int fd_; }; diff --git a/test/ipa/ipa_module_test.cpp b/test/ipa/ipa_module_test.cpp index 287e53fd..1c97da32 100644 --- a/test/ipa/ipa_module_test.cpp +++ b/test/ipa/ipa_module_test.cpp @@ -2,13 +2,13 @@ /* * Copyright (C) 2019, Google Inc. * - * ipa_module_test.cpp - Test loading of the VIMC IPA module and verify its info + * Test loading of the VIMC IPA module and verify its info */ #include <iostream> #include <string.h> -#include "ipa_module.h" +#include "libcamera/internal/ipa_module.h" #include "test.h" @@ -57,9 +57,8 @@ protected: const struct IPAModuleInfo testInfo = { IPA_MODULE_API_VERSION, 0, - "PipelineHandlerVimc", - "Dummy IPA for Vimc", - "GPL-2.0-or-later", + "vimc", + "vimc", }; count += runTest("src/ipa/vimc/ipa_vimc.so", testInfo); diff --git a/test/ipa/ipa_wrappers_test.cpp b/test/ipa/ipa_wrappers_test.cpp deleted file mode 100644 index 1ae17811..00000000 --- a/test/ipa/ipa_wrappers_test.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019, Google Inc. - * - * ipa_wrappers_test.cpp - Test the IPA interface and context wrappers - */ - -#include <fcntl.h> -#include <iostream> -#include <memory> -#include <linux/videodev2.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <libcamera/controls.h> -#include <libipa/ipa_interface_wrapper.h> - -#include "device_enumerator.h" -#include "ipa_context_wrapper.h" -#include "media_device.h" -#include "v4l2_subdevice.h" - -#include "test.h" - -using namespace libcamera; -using namespace std; - -enum Operation { - Op_init, - Op_configure, - Op_mapBuffers, - Op_unmapBuffers, - Op_processEvent, -}; - -class TestIPAInterface : public IPAInterface -{ -public: - TestIPAInterface() - : sequence_(0) - { - } - - int init() override - { - report(Op_init, TestPass); - return 0; - } - - void configure(const std::map<unsigned int, IPAStream> &streamConfig, - const std::map<unsigned int, const ControlInfoMap &> &entityControls) override - { - /* Verify streamConfig. */ - if (streamConfig.size() != 2) { - cerr << "configure(): Invalid number of streams " - << streamConfig.size() << endl; - return report(Op_configure, TestFail); - } - - auto iter = streamConfig.find(1); - if (iter == streamConfig.end()) { - cerr << "configure(): No configuration for stream 1" << endl; - return report(Op_configure, TestFail); - } - const IPAStream *stream = &iter->second; - if (stream->pixelFormat != V4L2_PIX_FMT_YUYV || - stream->size != Size{ 1024, 768 }) { - cerr << "configure(): Invalid configuration for stream 1" << endl; - return report(Op_configure, TestFail); - } - - iter = streamConfig.find(2); - if (iter == streamConfig.end()) { - cerr << "configure(): No configuration for stream 2" << endl; - return report(Op_configure, TestFail); - } - stream = &iter->second; - if (stream->pixelFormat != V4L2_PIX_FMT_NV12 || - stream->size != Size{ 800, 600 }) { - cerr << "configure(): Invalid configuration for stream 2" << endl; - return report(Op_configure, TestFail); - } - - /* Verify entityControls. */ - auto ctrlIter = entityControls.find(42); - if (ctrlIter == entityControls.end()) { - cerr << "configure(): Controls not found" << endl; - return report(Op_configure, TestFail); - } - - const ControlInfoMap &infoMap = ctrlIter->second; - - if (infoMap.count(V4L2_CID_BRIGHTNESS) != 1 || - infoMap.count(V4L2_CID_CONTRAST) != 1 || - infoMap.count(V4L2_CID_SATURATION) != 1) { - cerr << "configure(): Invalid control IDs" << endl; - return report(Op_configure, TestFail); - } - - report(Op_configure, TestPass); - } - - void mapBuffers(const std::vector<IPABuffer> &buffers) override - { - if (buffers.size() != 2) { - cerr << "mapBuffers(): Invalid number of buffers " - << buffers.size() << endl; - return report(Op_mapBuffers, TestFail); - } - - if (buffers[0].id != 10 || - buffers[1].id != 11) { - cerr << "mapBuffers(): Invalid buffer IDs" << endl; - return report(Op_mapBuffers, TestFail); - } - - if (buffers[0].planes.size() != 3 || - buffers[1].planes.size() != 3) { - cerr << "mapBuffers(): Invalid number of planes" << endl; - return report(Op_mapBuffers, TestFail); - } - - if (buffers[0].planes[0].length != 4096 || - buffers[0].planes[1].length != 0 || - buffers[0].planes[2].length != 0 || - buffers[0].planes[0].length != 4096 || - buffers[1].planes[1].length != 4096 || - buffers[1].planes[2].length != 0) { - cerr << "mapBuffers(): Invalid length" << endl; - return report(Op_mapBuffers, TestFail); - } - - if (buffers[0].planes[0].fd.fd() == -1 || - buffers[0].planes[1].fd.fd() != -1 || - buffers[0].planes[2].fd.fd() != -1 || - buffers[0].planes[0].fd.fd() == -1 || - buffers[1].planes[1].fd.fd() == -1 || - buffers[1].planes[2].fd.fd() != -1) { - cerr << "mapBuffers(): Invalid dmabuf" << endl; - return report(Op_mapBuffers, TestFail); - } - - report(Op_mapBuffers, TestPass); - } - - void unmapBuffers(const std::vector<unsigned int> &ids) override - { - if (ids.size() != 2) { - cerr << "unmapBuffers(): Invalid number of ids " - << ids.size() << endl; - return report(Op_unmapBuffers, TestFail); - } - - if (ids[0] != 10 || ids[1] != 11) { - cerr << "unmapBuffers(): Invalid buffer IDs" << endl; - return report(Op_unmapBuffers, TestFail); - } - - report(Op_unmapBuffers, TestPass); - } - - void processEvent(const IPAOperationData &data) override - { - /* Verify operation and data. */ - if (data.operation != Op_processEvent) { - cerr << "processEvent(): Invalid operation " - << data.operation << endl; - return report(Op_processEvent, TestFail); - } - - if (data.data != std::vector<unsigned int>{ 1, 2, 3, 4 }) { - cerr << "processEvent(): Invalid data" << endl; - return report(Op_processEvent, TestFail); - } - - /* Verify controls. */ - if (data.controls.size() != 1) { - cerr << "processEvent(): Controls not found" << endl; - return report(Op_processEvent, TestFail); - } - - const ControlList &controls = data.controls[0]; - if (controls.get(V4L2_CID_BRIGHTNESS).get<int32_t>() != 10 || - controls.get(V4L2_CID_CONTRAST).get<int32_t>() != 20 || - controls.get(V4L2_CID_SATURATION).get<int32_t>() != 30) { - cerr << "processEvent(): Invalid controls" << endl; - return report(Op_processEvent, TestFail); - } - - report(Op_processEvent, TestPass); - } - -private: - void report(Operation op, int status) - { - IPAOperationData data; - data.operation = op; - data.data.resize(1); - data.data[0] = status; - queueFrameAction.emit(sequence_++, data); - } - - unsigned int sequence_; -}; - -#define INVOKE(method, ...) \ - invoke(&IPAInterface::method, Op_##method, #method, ##__VA_ARGS__) - -class IPAWrappersTest : public Test -{ -public: - IPAWrappersTest() - : subdev_(nullptr), wrapper_(nullptr), sequence_(0), fd_(-1) - { - } - -protected: - int init() override - { - /* Locate the VIMC Sensor B subdevice. */ - enumerator_ = unique_ptr<DeviceEnumerator>(DeviceEnumerator::create()); - if (!enumerator_) { - cerr << "Failed to create device enumerator" << endl; - return TestFail; - } - - if (enumerator_->enumerate()) { - cerr << "Failed to enumerate media devices" << endl; - return TestFail; - } - - DeviceMatch dm("vimc"); - media_ = enumerator_->search(dm); - if (!media_) { - cerr << "No VIMC media device found: skip test" << endl; - return TestSkip; - } - - MediaEntity *entity = media_->getEntityByName("Sensor A"); - if (!entity) { - cerr << "Unable to find media entity 'Sensor A'" << endl; - return TestFail; - } - - subdev_ = new V4L2Subdevice(entity); - if (subdev_->open() < 0) { - cerr << "Unable to open 'Sensor A' subdevice" << endl; - return TestFail; - } - - /* Force usage of the C API as that's what we want to test. */ - int ret = setenv("LIBCAMERA_IPA_FORCE_C_API", "", 1); - if (ret) - return TestFail; - - std::unique_ptr<IPAInterface> intf = std::make_unique<TestIPAInterface>(); - wrapper_ = new IPAContextWrapper(new IPAInterfaceWrapper(std::move(intf))); - wrapper_->queueFrameAction.connect(this, &IPAWrappersTest::queueFrameAction); - - /* Create a file descriptor for the buffer-related operations. */ - fd_ = open("/tmp", O_TMPFILE | O_RDWR, 0600); - if (fd_ == -1) - return TestFail; - - ret = ftruncate(fd_, 4096); - if (ret < 0) - return TestFail; - - return TestPass; - } - - int run() override - { - int ret; - - /* Test configure(). */ - std::map<unsigned int, IPAStream> config{ - { 1, { V4L2_PIX_FMT_YUYV, { 1024, 768 } } }, - { 2, { V4L2_PIX_FMT_NV12, { 800, 600 } } }, - }; - std::map<unsigned int, const ControlInfoMap &> controlInfo; - controlInfo.emplace(42, subdev_->controls()); - ret = INVOKE(configure, config, controlInfo); - if (ret == TestFail) - return TestFail; - - /* Test mapBuffers(). */ - std::vector<IPABuffer> buffers(2); - buffers[0].planes.resize(3); - buffers[0].id = 10; - buffers[0].planes[0].fd = FileDescriptor(fd_); - buffers[0].planes[0].length = 4096; - buffers[1].id = 11; - buffers[1].planes.resize(3); - buffers[1].planes[0].fd = FileDescriptor(fd_); - buffers[1].planes[0].length = 4096; - buffers[1].planes[1].fd = FileDescriptor(fd_); - buffers[1].planes[1].length = 4096; - - ret = INVOKE(mapBuffers, buffers); - if (ret == TestFail) - return TestFail; - - /* Test unmapBuffers(). */ - std::vector<unsigned int> bufferIds = { 10, 11 }; - ret = INVOKE(unmapBuffers, bufferIds); - if (ret == TestFail) - return TestFail; - - /* Test processEvent(). */ - IPAOperationData data; - data.operation = Op_processEvent; - data.data = { 1, 2, 3, 4 }; - data.controls.emplace_back(subdev_->controls()); - - ControlList &controls = data.controls.back(); - controls.set(V4L2_CID_BRIGHTNESS, static_cast<int32_t>(10)); - controls.set(V4L2_CID_CONTRAST, static_cast<int32_t>(20)); - controls.set(V4L2_CID_SATURATION, static_cast<int32_t>(30)); - - ret = INVOKE(processEvent, data); - if (ret == TestFail) - return TestFail; - - /* - * Test init() last to ensure nothing in the wrappers or - * serializer depends on init() being called first. - */ - ret = INVOKE(init); - if (ret == TestFail) - return TestFail; - - return TestPass; - } - - void cleanup() override - { - delete wrapper_; - delete subdev_; - - if (fd_ != -1) - close(fd_); - } - -private: - template<typename T, typename... Args1, typename... Args2> - int invoke(T (IPAInterface::*func)(Args1...), Operation op, - const char *name, Args2... args) - { - data_ = IPAOperationData(); - (wrapper_->*func)(args...); - - if (frame_ != sequence_) { - cerr << "IPAInterface::" << name - << "(): invalid frame number " << frame_ - << ", expected " << sequence_; - return TestFail; - } - - sequence_++; - - if (data_.operation != op) { - cerr << "IPAInterface::" << name - << "(): failed to propagate" << endl; - return TestFail; - } - - if (data_.data[0] != TestPass) { - cerr << "IPAInterface::" << name - << "(): reported an error" << endl; - return TestFail; - } - - return TestPass; - } - - void queueFrameAction(unsigned int frame, const IPAOperationData &data) - { - frame_ = frame; - data_ = data; - } - - std::shared_ptr<MediaDevice> media_; - std::unique_ptr<DeviceEnumerator> enumerator_; - V4L2Subdevice *subdev_; - - IPAContextWrapper *wrapper_; - IPAOperationData data_; - unsigned int sequence_; - unsigned int frame_; - int fd_; -}; - -TEST_REGISTER(IPAWrappersTest) diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp new file mode 100644 index 00000000..99eb662d --- /dev/null +++ b/test/ipa/libipa/fixedpoint.cpp @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com> + * + * Fixed / Floating point utility tests + */ + +#include <cmath> +#include <iostream> +#include <map> +#include <stdint.h> + +#include "../src/ipa/libipa/fixedpoint.h" + +#include "test.h" + +using namespace std; +using namespace libcamera; +using namespace ipa; + +class FixedPointUtilsTest : public Test +{ +protected: + /* R for real, I for integer */ + template<unsigned int IntPrec, unsigned int FracPrec, typename I, typename R> + int testFixedToFloat(I input, R expected) + { + R out = fixedToFloatingPoint<IntPrec, FracPrec, R>(input); + R prec = 1.0 / (1 << FracPrec); + if (std::abs(out - expected) > prec) { + cerr << "Reverse conversion expected " << input + << " to convert to " << expected + << ", got " << out << std::endl; + return TestFail; + } + + return TestPass; + } + + template<unsigned int IntPrec, unsigned int FracPrec, typename T> + int testSingleFixedPoint(double input, T expected) + { + T ret = floatingToFixedPoint<IntPrec, FracPrec, T>(input); + if (ret != expected) { + cerr << "Expected " << input << " to convert to " + << expected << ", got " << ret << std::endl; + return TestFail; + } + + /* + * The precision check is fairly arbitrary but is based on what + * the rkisp1 is capable of in the crosstalk module. + */ + double f = fixedToFloatingPoint<IntPrec, FracPrec, double>(ret); + if (std::abs(f - input) > 0.005) { + cerr << "Reverse conversion expected " << ret + << " to convert to " << input + << ", got " << f << std::endl; + return TestFail; + } + + return TestPass; + } + + int testFixedPoint() + { + /* + * The second 7.992 test is to test that unused bits don't + * affect the result. + */ + std::map<double, uint16_t> testCases = { + { 7.992, 0x3ff }, + { 0.2, 0x01a }, + { -0.2, 0x7e6 }, + { -0.8, 0x79a }, + { -0.4, 0x7cd }, + { -1.4, 0x74d }, + { -8, 0x400 }, + { 0, 0 }, + }; + + int ret; + for (const auto &testCase : testCases) { + ret = testSingleFixedPoint<4, 7, uint16_t>(testCase.first, + testCase.second); + if (ret != TestPass) + return ret; + } + + /* Special case with a superfluous one in the unused bits */ + ret = testFixedToFloat<4, 7, uint16_t, double>(0xbff, 7.992); + if (ret != TestPass) + return ret; + + return TestPass; + } + + int run() + { + /* fixed point conversion test */ + if (testFixedPoint() != TestPass) + return TestFail; + + return TestPass; + } +}; + +TEST_REGISTER(FixedPointUtilsTest) diff --git a/test/ipa/libipa/interpolator.cpp b/test/ipa/libipa/interpolator.cpp new file mode 100644 index 00000000..6abb7760 --- /dev/null +++ b/test/ipa/libipa/interpolator.cpp @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024, Ideas on Board Oy + * + * Interpolator tests + */ + +#include "../src/ipa/libipa/interpolator.h" + +#include <cmath> +#include <iostream> +#include <map> +#include <stdint.h> +#include <stdio.h> + +#include "test.h" + +using namespace std; +using namespace libcamera; +using namespace ipa; + +#define ASSERT_EQ(a, b) \ + if ((a) != (b)) { \ + printf(#a " != " #b "\n"); \ + return TestFail; \ + } + +class InterpolatorTest : public Test +{ +protected: + int run() + { + Interpolator<int> interpolator; + interpolator.setData({ { 10, 100 }, { 20, 200 }, { 30, 300 } }); + + ASSERT_EQ(interpolator.getInterpolated(0), 100); + ASSERT_EQ(interpolator.getInterpolated(10), 100); + ASSERT_EQ(interpolator.getInterpolated(20), 200); + ASSERT_EQ(interpolator.getInterpolated(25), 250); + ASSERT_EQ(interpolator.getInterpolated(30), 300); + ASSERT_EQ(interpolator.getInterpolated(40), 300); + + interpolator.setQuantization(10); + unsigned int q = 0; + ASSERT_EQ(interpolator.getInterpolated(25, &q), 300); + ASSERT_EQ(q, 30); + ASSERT_EQ(interpolator.getInterpolated(24, &q), 200); + ASSERT_EQ(q, 20); + + return TestPass; + } +}; + +TEST_REGISTER(InterpolatorTest) diff --git a/test/ipa/libipa/meson.build b/test/ipa/libipa/meson.build new file mode 100644 index 00000000..0f4155d2 --- /dev/null +++ b/test/ipa/libipa/meson.build @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: CC0-1.0 + +libipa_test = [ + {'name': 'fixedpoint', 'sources': ['fixedpoint.cpp']}, + {'name': 'interpolator', 'sources': ['interpolator.cpp']}, + {'name': 'vector', 'sources': ['vector.cpp']}, +] + +foreach test : libipa_test + exe = executable(test['name'], test['sources'], + dependencies : [libcamera_private, libipa_dep], + implicit_include_directories : false, + link_with : [test_libraries], + include_directories : [test_includes_internal, + '../../../src/ipa/libipa/']) + + test(test['name'], exe, suite : 'ipa') +endforeach diff --git a/test/ipa/libipa/vector.cpp b/test/ipa/libipa/vector.cpp new file mode 100644 index 00000000..8e4ec77d --- /dev/null +++ b/test/ipa/libipa/vector.cpp @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024, Ideas on Board Oy + * + * Vector tests + */ + +#include "../src/ipa/libipa/vector.h" + +#include <cmath> +#include <iostream> + +#include "test.h" + +using namespace libcamera::ipa; + +#define ASSERT_EQ(a, b) \ +if ((a) != (b)) { \ + std::cout << #a " != " #b << " (line " << __LINE__ << ")" \ + << std::endl; \ + return TestFail; \ +} + +class VectorTest : public Test +{ +protected: + int run() + { + Vector<double, 3> v1{ 0.0 }; + + ASSERT_EQ(v1[0], 0.0); + ASSERT_EQ(v1[1], 0.0); + ASSERT_EQ(v1[2], 0.0); + + ASSERT_EQ(v1.length(), 0.0); + ASSERT_EQ(v1.length2(), 0.0); + + Vector<double, 3> v2{{ 1.0, 4.0, 8.0 }}; + + ASSERT_EQ(v2[0], 1.0); + ASSERT_EQ(v2[1], 4.0); + ASSERT_EQ(v2[2], 8.0); + + ASSERT_EQ(v2.x(), 1.0); + ASSERT_EQ(v2.y(), 4.0); + ASSERT_EQ(v2.z(), 8.0); + + ASSERT_EQ(v2.r(), 1.0); + ASSERT_EQ(v2.g(), 4.0); + ASSERT_EQ(v2.b(), 8.0); + + ASSERT_EQ(v2.length2(), 81.0); + ASSERT_EQ(v2.length(), 9.0); + ASSERT_EQ(v2.sum(), 13.0); + + Vector<double, 3> v3{ v2 }; + + ASSERT_EQ(v2, v3); + + v3 = Vector<double, 3>{{ 4.0, 4.0, 4.0 }}; + + ASSERT_EQ(v2 + v3, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + ASSERT_EQ(v2 + 4.0, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + ASSERT_EQ(v2 - v3, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }})); + ASSERT_EQ(v2 - 4.0, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }})); + ASSERT_EQ(v2 * v3, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + ASSERT_EQ(v2 * 4.0, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + ASSERT_EQ(v2 / v3, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }})); + ASSERT_EQ(v2 / 4.0, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }})); + + ASSERT_EQ(v2.min(v3), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }})); + ASSERT_EQ(v2.min(4.0), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }})); + ASSERT_EQ(v2.max(v3), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }})); + ASSERT_EQ(v2.max(4.0), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }})); + + ASSERT_EQ(v2.dot(v3), 52.0); + + v2 += v3; + ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + v2 -= v3; + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + v2 *= v3; + ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + v2 /= v3; + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + + v2 += 4.0; + ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }})); + v2 -= 4.0; + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + v2 *= 4.0; + ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }})); + v2 /= 4.0; + ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }})); + + return TestPass; + } +}; + +TEST_REGISTER(VectorTest) diff --git a/test/ipa/meson.build b/test/ipa/meson.build index f925c50a..ceed15ba 100644 --- a/test/ipa/meson.build +++ b/test/ipa/meson.build @@ -1,14 +1,17 @@ +# SPDX-License-Identifier: CC0-1.0 + +subdir('libipa') + ipa_test = [ - ['ipa_module_test', 'ipa_module_test.cpp'], - ['ipa_interface_test', 'ipa_interface_test.cpp'], - ['ipa_wrappers_test', 'ipa_wrappers_test.cpp'], + {'name': 'ipa_module_test', 'sources': ['ipa_module_test.cpp']}, + {'name': 'ipa_interface_test', 'sources': ['ipa_interface_test.cpp']}, ] -foreach t : ipa_test - exe = executable(t[0], t[1], - dependencies : libcamera_dep, - link_with : [libipa, test_libraries], - include_directories : [libipa_includes, test_includes_internal]) +foreach test : ipa_test + exe = executable(test['name'], test['sources'], + dependencies : [libcamera_private, libipa_dep], + link_with : [test_libraries], + include_directories : [test_includes_internal]) - test(t[0], exe, suite : 'ipa') + test(test['name'], exe, suite : 'ipa') endforeach |