From patchwork Wed Mar 13 12:12:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 19706 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 6B6B7BD160 for ; Wed, 13 Mar 2024 12:12:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AC7E862CA8; Wed, 13 Mar 2024 13:12:51 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Q/v6zje0"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D261762C86 for ; Wed, 13 Mar 2024 13:12:44 +0100 (CET) Received: from jasper.fritz.box (unknown [IPv6:2a00:6020:448c:6c00:9b07:31b5:38e1:e957]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 59187A8F; Wed, 13 Mar 2024 13:12:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1710331942; bh=7oapYLMN7cyigWB9FuJ2msVMCOH06w430iE+QjjU9L0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Q/v6zje0Sb1f4w/LjORQklrlrqAIvnbI9qpIRRLSrbMr91WzXMS5QKduBxCvr+SPH pRfM4weyi3z01pL3NwVC5AgCg2o5qqHja0ToTVAJn/NrDjbF3Kl9zikiKL1clAn0KP Re/nP1XfgeaXyxChzaASURxCq9EZUnKZZ8E0klvI= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Subject: [PATCH v2 04/12] libcamera: delayed_controls: Update unit tests to expected semantics Date: Wed, 13 Mar 2024 13:12:15 +0100 Message-Id: <20240313121223.138150-5-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240313121223.138150-1-stefan.klug@ideasonboard.com> References: <20240313121223.138150-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stefan Klug Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" This patches changes the tests in a way DelayedControls is expected to work. It does not require a interface change in DelayedControls. The changes are: - It is expected that for every apply() there was a previous push(). - When a control is pushed for frame 0, that request is not lost, but applied as soon as possible Signed-off-by: Stefan Klug --- test/delayed_controls.cpp | 203 +++++++++++++++++++++++++++++--------- 1 file changed, 156 insertions(+), 47 deletions(-) diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp index a8ce9828..e0634fa1 100644 --- a/test/delayed_controls.cpp +++ b/test/delayed_controls.cpp @@ -84,11 +84,8 @@ protected: dev_->setControls(&ctrls); delayed->reset(); - /* Trigger the first frame start event */ - delayed->applyControls(0); - /* Test control without delay are set at once. */ - for (unsigned int i = 1; i < 100; i++) { + for (unsigned int i = 0; i < 100; i++) { int32_t value = 100 + i; ctrls.set(V4L2_CID_BRIGHTNESS, value); @@ -121,25 +118,30 @@ protected: ControlList ctrls; /* Reset control to value that will be first in test. */ - int32_t expected = 4; - ctrls.set(V4L2_CID_BRIGHTNESS, expected); + int32_t initial = 4; + ctrls.set(V4L2_CID_BRIGHTNESS, initial); dev_->setControls(&ctrls); delayed->reset(); - /* Trigger the first frame start event */ - delayed->applyControls(0); + /* Push a request for frame 0 */ + ctrls.set(V4L2_CID_BRIGHTNESS, 10); + delayed->push(ctrls); /* Test single control with delay. */ - for (unsigned int i = 1; i < 100; i++) { + for (unsigned int i = 0; i < 100; i++) { int32_t value = 10 + i; + int32_t expected = i < 1 ? initial : value; - ctrls.set(V4L2_CID_BRIGHTNESS, value); + /* push the request for frame i+1 */ + ctrls.set(V4L2_CID_BRIGHTNESS, value + 1); delayed->push(ctrls); delayed->applyControls(i); ControlList result = delayed->get(i); int32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get(); + ControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS }); + int32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get(); if (brightness != expected) { cerr << "Failed single control with delay" << " frame " << i @@ -149,7 +151,72 @@ protected: return TestFail; } - expected = value; + if (i > 0 && brightnessV4L != value + 1) { + cerr << "Failed single control with delay" + << " frame " << i + << " expected V4L " << value + 1 + << " got " << brightnessV4L + << endl; + return TestFail; + } + } + + return TestPass; + } + + /* This fails on the old delayed controls implementation */ + int singleControlWithDelayStartUp() + { + std::unordered_map delays = { + { V4L2_CID_BRIGHTNESS, { 1, false } }, + }; + std::unique_ptr delayed = + std::make_unique(dev_.get(), delays); + ControlList ctrls; + + /* Reset control to value that will be first in test. */ + int32_t initial = 4; + ctrls.set(V4L2_CID_BRIGHTNESS, initial); + dev_->setControls(&ctrls); + delayed->reset(); + + /* push a request for frame 0 */ + ctrls.set(V4L2_CID_BRIGHTNESS, 10); + delayed->push(ctrls); + + /* Test single control with delay. */ + for (unsigned int i = 0; i < 100; i++) { + int32_t value = 10 + i; + int32_t expected = i < 1 ? initial : value; + + /* push the request for frame i+1 */ + ctrls.set(V4L2_CID_BRIGHTNESS, value + 1); + delayed->push(ctrls); + + delayed->applyControls(i); + + ControlList result = delayed->get(i); + int32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get(); + ControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS }); + int32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get(); + + if (brightness != expected) { + cerr << "Failed single control with delay start up" + << " frame " << i + << " expected " << expected + << " got " << brightness + << endl; + return TestFail; + } + + if (i > 0 && brightnessV4L != value + 1) { + cerr << "Failed single control with delay start up" + << " frame " << i + << " expected V4L " << value + 1 + << " got " << brightnessV4L + << endl; + return TestFail; + } } return TestPass; @@ -157,7 +224,7 @@ protected: int dualControlsWithDelay() { - static const unsigned int maxDelay = 2; + static const int maxDelay = 2; std::unordered_map delays = { { V4L2_CID_BRIGHTNESS, { 1, false } }, @@ -174,15 +241,21 @@ protected: dev_->setControls(&ctrls); delayed->reset(); - /* Trigger the first frame start event */ - delayed->applyControls(0); + /* push two requests into the queue */ + ctrls.set(V4L2_CID_BRIGHTNESS, 10); + ctrls.set(V4L2_CID_CONTRAST, 10); + delayed->push(ctrls); + ctrls.set(V4L2_CID_BRIGHTNESS, 11); + ctrls.set(V4L2_CID_CONTRAST, 11); + delayed->push(ctrls); /* Test dual control with delay. */ - for (unsigned int i = 1; i < 100; i++) { + for (unsigned int i = 0; i < 100; i++) { int32_t value = 10 + i; - ctrls.set(V4L2_CID_BRIGHTNESS, value); - ctrls.set(V4L2_CID_CONTRAST, value + 1); + /* we are pushing 2 frames ahead */ + ctrls.set(V4L2_CID_BRIGHTNESS, value + 2); + ctrls.set(V4L2_CID_CONTRAST, value + 2); delayed->push(ctrls); delayed->applyControls(i); @@ -190,17 +263,32 @@ protected: ControlList result = delayed->get(i); int32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get(); int32_t contrast = result.get(V4L2_CID_CONTRAST).get(); - if (brightness != expected || contrast != expected + 1) { - cerr << "Failed dual controls" - << " frame " << i - << " brightness " << brightness - << " contrast " << contrast - << " expected " << expected - << endl; - return TestFail; - } - expected = i < maxDelay ? expected : value - 1; + ControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST }); + int32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get(); + int32_t contrastV4L = ctrlsV4L.get(V4L2_CID_CONTRAST).get(); + + if (i > maxDelay) { + if (brightness != value || contrast != value) { + cerr << "Failed dual controls" + << " frame " << i + << " brightness " << brightness + << " contrast " << contrast + << " expected " << value + << endl; + return TestFail; + } + if (brightnessV4L != value + 1 || contrastV4L != value + maxDelay) { + cerr << "Failed dual controls" + << " frame " << i + << " brightnessV4L " << brightnessV4L + << " expected " << value + 1 + << " contrastV4L " << contrastV4L + << " expected " << value + maxDelay + << endl; + return TestFail; + } + } } return TestPass; @@ -208,7 +296,7 @@ protected: int dualControlsMultiQueue() { - static const unsigned int maxDelay = 2; + static const int maxDelay = 2; std::unordered_map delays = { { V4L2_CID_BRIGHTNESS, { 1, false } }, @@ -218,22 +306,19 @@ protected: std::make_unique(dev_.get(), delays); ControlList ctrls; - /* Reset control to value that will be first two frames in test. */ - int32_t expected = 100; - ctrls.set(V4L2_CID_BRIGHTNESS, expected); - ctrls.set(V4L2_CID_CONTRAST, expected); + /* Reset control to a value that will be first two frames in test. */ + int32_t initial = 100; + ctrls.set(V4L2_CID_BRIGHTNESS, initial); + ctrls.set(V4L2_CID_CONTRAST, initial); dev_->setControls(&ctrls); delayed->reset(); - /* Trigger the first frame start event */ - delayed->applyControls(0); - /* - * Queue all controls before any fake frame start. Note we + * Queue all controls before applyControls(). Note we * can't queue up more then the delayed controls history size - * which is 16. Where one spot is used by the reset control. + * which is 16. */ - for (unsigned int i = 0; i < 15; i++) { + for (unsigned int i = 0; i < 14; i++) { int32_t value = 10 + i; ctrls.set(V4L2_CID_BRIGHTNESS, value); @@ -241,9 +326,9 @@ protected: delayed->push(ctrls); } - /* Process all queued controls. */ - for (unsigned int i = 1; i < 16; i++) { - int32_t value = 10 + i - 1; + /* Process 2 frames less than queued, so that the V4L controls are correct */ + for (unsigned int i = 0; i < 12; i++) { + int32_t expected = i < maxDelay ? initial : 10 + i; delayed->applyControls(i); @@ -251,6 +336,11 @@ protected: int32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get(); int32_t contrast = result.get(V4L2_CID_CONTRAST).get(); + + ControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST }); + int32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get(); + int32_t contrastV4L = ctrlsV4L.get(V4L2_CID_CONTRAST).get(); + if (brightness != expected || contrast != expected) { cerr << "Failed multi queue" << " frame " << i @@ -261,7 +351,17 @@ protected: return TestFail; } - expected = i < maxDelay ? expected : value - 1; + /* Check v4l values after they've settled */ + if (i >= maxDelay && (brightnessV4L != expected + 1 || contrastV4L != expected + maxDelay)) { + cerr << "Failed multi queue" + << " frame " << i + << " brightnessV4L " << brightnessV4L + << " expected " << expected + 1 + << " contrastV4L " << contrastV4L + << " expected " << expected + maxDelay + << endl; + return TestFail; + } } return TestPass; @@ -269,27 +369,36 @@ protected: int run() override { - int ret; + int ret = 0; + bool failed = false; /* Test single control without delay. */ ret = singleControlNoDelay(); if (ret) - return ret; + failed = true; /* Test single control with delay. */ ret = singleControlWithDelay(); if (ret) - return ret; + failed = true; + + /* Test single control with delay. */ + ret = singleControlWithDelayStartUp(); + if (ret) + failed = true; /* Test dual controls with different delays. */ ret = dualControlsWithDelay(); if (ret) - return ret; + failed = true; /* Test control values produced faster than consumed. */ ret = dualControlsMultiQueue(); if (ret) - return ret; + failed = true; + + if (failed) + return TestFail; return TestPass; }