From patchwork Thu Jan 21 11:58:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 10923 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 710D2C0F2A for ; Thu, 21 Jan 2021 11:58:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3CFFE681EE; Thu, 21 Jan 2021 12:58:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="dNRTyvnk"; dkim-atps=neutral Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 15BFE681C8 for ; Thu, 21 Jan 2021 12:58:55 +0100 (CET) Received: by mail-wm1-x32d.google.com with SMTP id j18so1213131wmi.3 for ; Thu, 21 Jan 2021 03:58:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RlcCs85RsvREHCFk25gd9h0IFdCVRIaWFJ7wNCTORis=; b=dNRTyvnkewf0xKlhHFGRWRF5nP24Tj31GLFtltRv4HnYZbUXqbERgC6Xx+G6JiOoQu Nwvk+C+PUx1LdCWcC9dQBq9HoOWlrGxiDcg1pVyugTCC9zpOD4E6NDitVZS7SEsRZxeS NMhoYYDiwuce0Ap7knedpA9H3EGuN/MlDxbK3MNz1NTGFgDz06rWpqE7rbFNdgOTSesv JZt90ZVwCEp6nr5BuA2UootFWhLi9rlxNwNovc+ik2ll5WtE8zOq0lfIsptqnjkbhS5i yD2FzvNSXv5YbliIXNdhdvACfEnrkYMgTDhFIjXHZzc4Tm/yxxhOG4NGg6VUPQG+CSen sREA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RlcCs85RsvREHCFk25gd9h0IFdCVRIaWFJ7wNCTORis=; b=emSLpz/fX+r65O6+xXAjAEAbT/Ro/vONSSO+ndhgHv92carpuzrHDBhYNkKkT2rdok grGw4JIDeYPfL4o1+OI0TMUsJDVCX16P8AJQvz/PD8sDiA0FKxmxKfiDd7xeiLEg9kor NP6YU2x4l/Fr01m+5I1mAku1zo/6tHQkikPivyo5fgt+yXk08IE/u+V9AKe2EEnueyu7 uFrhlUs7pIyPjYq6kgsJec6qj4Shm6IwS74HcnWvLnnk/0DU/tMnpNRSK5cEWtT+t/R2 kl4Cdamk3FIRfKrbFO3cHZfxDUtNcRgZOqQyhAFOgWNE/STpsefaehTjTwEynm1E9QhI nghw== X-Gm-Message-State: AOAM532JfgIMJ/x32fpJ/6b8Zgl1ImYJdX4569OHdERhM1M+QyO8cxtF ovjcCf6XxNywZ4UdDTTFAzK1vK8+LLWp+g== X-Google-Smtp-Source: ABdhPJxmM6NlXRB8fTThFLyqLrZ/ENLHAQdsvh0qbShrpx2bp+REwMVMiKwpZ4W6G8rCJmR87fl0cw== X-Received: by 2002:a05:600c:2a47:: with SMTP id x7mr8529219wme.145.1611230334617; Thu, 21 Jan 2021 03:58:54 -0800 (PST) Received: from naushir-VirtualBox.patuck.local ([88.97.76.4]) by smtp.gmail.com with ESMTPSA id h13sm8044930wrm.28.2021.01.21.03.58.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Jan 2021 03:58:53 -0800 (PST) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Thu, 21 Jan 2021 11:58:46 +0000 Message-Id: <20210121115849.682130-2-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210121115849.682130-1-naush@raspberrypi.com> References: <20210121115849.682130-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/4] raspberrypi: Add the correct integer const postfix for FrameDurations 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" At startup, ControlInfoMap::generateIdmap() threw a log message warning that the controls::FrameDurations had a type mismatch based on the min/max values provided in libcamera::RPi::Controls initialiser. Fix this warning by adding and explicit int64_t postfix to the const values for min and max. Signed-off-by: Naushir Patuck Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- include/libcamera/ipa/raspberrypi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libcamera/ipa/raspberrypi.h b/include/libcamera/ipa/raspberrypi.h index 1de36039cee0..8e704d922ce6 100644 --- a/include/libcamera/ipa/raspberrypi.h +++ b/include/libcamera/ipa/raspberrypi.h @@ -65,7 +65,7 @@ static const ControlInfoMap Controls = { { &controls::Sharpness, ControlInfo(0.0f, 16.0f, 1.0f) }, { &controls::ColourCorrectionMatrix, ControlInfo(-16.0f, 16.0f) }, { &controls::ScalerCrop, ControlInfo(Rectangle{}, Rectangle(65535, 65535, 65535, 65535), Rectangle{}) }, - { &controls::FrameDurations, ControlInfo(1000, 1000000000) }, + { &controls::FrameDurations, ControlInfo(INT64_C(1000), INT64_C(1000000000)) }, }; } /* namespace RPi */ From patchwork Thu Jan 21 11:58:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 10924 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 31D75C0F2A for ; Thu, 21 Jan 2021 11:58:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9416E681E8; Thu, 21 Jan 2021 12:58:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="Yz7fqqyL"; dkim-atps=neutral Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8542E68193 for ; Thu, 21 Jan 2021 12:58:56 +0100 (CET) Received: by mail-wr1-x433.google.com with SMTP id g10so1471124wrx.1 for ; Thu, 21 Jan 2021 03:58:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=I6nbokmU1UFmWGgvXBfDE4GaCEaupfvnKwSGytxLa1g=; b=Yz7fqqyLGqqjr6JlhxHpvMZsgHlqeHvwrqUhuYCoWoSm90u0wUVu5XMFffK/pjv+O9 oVDJvbKXXuDJQv0LzDzTEIgeSjajZ7x3Pye6iO6AfaITMz5r4WlWSaQiD1Iph4PLBxL6 2t2YLX85S3dhBmsNWYKKWnWZoGpH5IMFOa8PM7RP+FYYFUdGHYxA/rVzHsuFJ7B1JIAH uio0clqySmab7iEwgAFDr7YVIhsLBC/y8bCCwEqhzGimvnhljy8OkWnuMkudIuyDNuL3 A2x4qlxgTHLRMtOyE5V8ID7obgwfndi+CmgdhkQ4e0Gc5vve8ggzCdPN+U5urJamHdDt xwXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=I6nbokmU1UFmWGgvXBfDE4GaCEaupfvnKwSGytxLa1g=; b=VnKMRuGWEuEMI13gaKmo3ftdS+vwSF9Ba9unJfewSI0yF+lwqPYhIclPC4va4kVsns L6nNjc0EXnuNplqC9q2KqJJWP3vjI5JVBmos8bBUwW0yC2Dfbprk1V2wrTNlLuMENHPR 6unLdUKlMEF/hBugVtOjcPa93rnONsg2BD93Oaq1S278HNs4OIM9jaEt9f6ohY9hGqGR FF2ny+JW6m6bAOcZ8XN3uxJFd4/U6hTGGvcU8bWIh0hztOFUcSi7yEo2CoLKrhEg/Q/7 vmmk5xs+DjPr6SXI3HPS+ka9wSZwzhYPPT6TJuilUB/95zf5FCg14RaLEOoYVmw7JSrC lGZg== X-Gm-Message-State: AOAM530KnfRP+YWru+hlZBqGSsWCblobUzJYbhTFKMqxFjB65BXNIGh5 LI8V4TV8gGqwwM0NCkF1AlgaXxu7xuwMfw== X-Google-Smtp-Source: ABdhPJwMbS1xqfigSSJl8J+EkgpZmCsVmMEvfjZjao5C1RuU9aZXdAA91AxJ7rm+B63C2HAsAXSR3g== X-Received: by 2002:adf:ef03:: with SMTP id e3mr9771666wro.98.1611230335633; Thu, 21 Jan 2021 03:58:55 -0800 (PST) Received: from naushir-VirtualBox.patuck.local ([88.97.76.4]) by smtp.gmail.com with ESMTPSA id h13sm8044930wrm.28.2021.01.21.03.58.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Jan 2021 03:58:55 -0800 (PST) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Thu, 21 Jan 2021 11:58:47 +0000 Message-Id: <20210121115849.682130-3-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210121115849.682130-1-naush@raspberrypi.com> References: <20210121115849.682130-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/4] ipa: raspberrypi: Limit the calculated vblank based on the sensor mode 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The existing framerate/vblank calculations did not account for the sensor mode limits. This commit extracts vblank limits from the sensor v4l2 controls, and stores it in the camera modes structure. Exposure and vblank value calculations now use values clamped to the sensor mode limits. The libcamera::controls::FrameDurations metadata return values now reflect the minimum and maximum after clamping. Signed-off-by: Naushir Patuck Reviewed-by: David Plowman --- src/ipa/raspberrypi/cam_helper.cpp | 16 +++--- src/ipa/raspberrypi/cam_helper.hpp | 5 +- src/ipa/raspberrypi/cam_helper_imx219.cpp | 6 +-- src/ipa/raspberrypi/cam_helper_imx477.cpp | 4 +- src/ipa/raspberrypi/cam_helper_ov5647.cpp | 4 +- src/ipa/raspberrypi/controller/camera_mode.h | 2 + src/ipa/raspberrypi/raspberrypi.cpp | 51 ++++++++++++++------ 7 files changed, 49 insertions(+), 39 deletions(-) diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp index b7b8faf09c69..3e17255737b2 100644 --- a/src/ipa/raspberrypi/cam_helper.cpp +++ b/src/ipa/raspberrypi/cam_helper.cpp @@ -34,9 +34,8 @@ CamHelper *CamHelper::Create(std::string const &cam_name) return nullptr; } -CamHelper::CamHelper(MdParser *parser, unsigned int maxFrameLength, - unsigned int frameIntegrationDiff) - : parser_(parser), initialized_(false), maxFrameLength_(maxFrameLength), +CamHelper::CamHelper(MdParser *parser, unsigned int frameIntegrationDiff) + : parser_(parser), initialized_(false), frameIntegrationDiff_(frameIntegrationDiff) { } @@ -67,13 +66,12 @@ uint32_t CamHelper::GetVBlanking(double &exposure, double minFrameDuration, assert(initialized_); /* - * Clamp frame length by the frame duration range and the maximum allowable - * value in the sensor, given by maxFrameLength_. + * minFrameDuration and maxFrameDuration will have been clamped to the + * maximum allowable values in the sensor for this mode. */ - frameLengthMin = std::clamp(1e3 * minFrameDuration / mode_.line_length, - mode_.height, maxFrameLength_); - frameLengthMax = std::clamp(1e3 * maxFrameDuration / mode_.line_length, - mode_.height, maxFrameLength_); + frameLengthMin = 1e3 * minFrameDuration / mode_.line_length; + frameLengthMax = 1e3 * maxFrameDuration / mode_.line_length; + /* * Limit the exposure to the maximum frame duration requested, and * re-calculate if it has been clipped. diff --git a/src/ipa/raspberrypi/cam_helper.hpp b/src/ipa/raspberrypi/cam_helper.hpp index b1739a57e342..14d70112cb62 100644 --- a/src/ipa/raspberrypi/cam_helper.hpp +++ b/src/ipa/raspberrypi/cam_helper.hpp @@ -62,8 +62,7 @@ class CamHelper { public: static CamHelper *Create(std::string const &cam_name); - CamHelper(MdParser *parser, unsigned int maxFrameLength, - unsigned int frameIntegrationDiff); + CamHelper(MdParser *parser, unsigned int frameIntegrationDiff); virtual ~CamHelper(); void SetCameraMode(const CameraMode &mode); MdParser &Parser() const { return *parser_; } @@ -86,8 +85,6 @@ protected: private: bool initialized_; - /* Largest possible frame length, in units of lines. */ - unsigned int maxFrameLength_; /* * Smallest difference between the frame length and integration time, * in units of lines. diff --git a/src/ipa/raspberrypi/cam_helper_imx219.cpp b/src/ipa/raspberrypi/cam_helper_imx219.cpp index 8688ec091c44..95b8e698fe3b 100644 --- a/src/ipa/raspberrypi/cam_helper_imx219.cpp +++ b/src/ipa/raspberrypi/cam_helper_imx219.cpp @@ -56,15 +56,13 @@ private: * in units of lines. */ static constexpr int frameIntegrationDiff = 4; - /* Largest possible frame length, in units of lines. */ - static constexpr int maxFrameLength = 0xffff; }; CamHelperImx219::CamHelperImx219() #if ENABLE_EMBEDDED_DATA - : CamHelper(new MdParserImx219(), maxFrameLength, frameIntegrationDiff) + : CamHelper(new MdParserImx219(), frameIntegrationDiff) #else - : CamHelper(new MdParserRPi(), maxFrameLength, frameIntegrationDiff) + : CamHelper(new MdParserRPi(), frameIntegrationDiff) #endif { } diff --git a/src/ipa/raspberrypi/cam_helper_imx477.cpp b/src/ipa/raspberrypi/cam_helper_imx477.cpp index 5396131003f1..eaa7be16d20e 100644 --- a/src/ipa/raspberrypi/cam_helper_imx477.cpp +++ b/src/ipa/raspberrypi/cam_helper_imx477.cpp @@ -45,12 +45,10 @@ private: * in units of lines. */ static constexpr int frameIntegrationDiff = 22; - /* Largest possible frame length, in units of lines. */ - static constexpr int maxFrameLength = 0xffdc; }; CamHelperImx477::CamHelperImx477() - : CamHelper(new MdParserImx477(), maxFrameLength, frameIntegrationDiff) + : CamHelper(new MdParserImx477(), frameIntegrationDiff) { } diff --git a/src/ipa/raspberrypi/cam_helper_ov5647.cpp b/src/ipa/raspberrypi/cam_helper_ov5647.cpp index 2bd8a754f133..a7f417324048 100644 --- a/src/ipa/raspberrypi/cam_helper_ov5647.cpp +++ b/src/ipa/raspberrypi/cam_helper_ov5647.cpp @@ -30,8 +30,6 @@ private: * in units of lines. */ static constexpr int frameIntegrationDiff = 4; - /* Largest possible frame length, in units of lines. */ - static constexpr int maxFrameLength = 0xffff; }; /* @@ -40,7 +38,7 @@ private: */ CamHelperOv5647::CamHelperOv5647() - : CamHelper(new MdParserRPi(), maxFrameLength, frameIntegrationDiff) + : CamHelper(new MdParserRPi(), frameIntegrationDiff) { } diff --git a/src/ipa/raspberrypi/controller/camera_mode.h b/src/ipa/raspberrypi/controller/camera_mode.h index 920f11beb0b0..3baeadaca076 100644 --- a/src/ipa/raspberrypi/controller/camera_mode.h +++ b/src/ipa/raspberrypi/controller/camera_mode.h @@ -37,6 +37,8 @@ struct CameraMode { double line_length; // any camera transform *not* reflected already in the camera tuning libcamera::Transform transform; + // minimum and maximum vblanking limits for this mode + uint32_t vblank_min, vblank_max; }; #ifdef __cplusplus diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp index 5ccc7a6551f5..9e6e030c4997 100644 --- a/src/ipa/raspberrypi/raspberrypi.cpp +++ b/src/ipa/raspberrypi/raspberrypi.cpp @@ -102,6 +102,7 @@ private: void reportMetadata(); bool parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus); void processStats(unsigned int bufferId); + void applyFrameDurations(double min, double max); void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls); void applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls); void applyDG(const struct AgcStatus *dgStatus, ControlList &ctrls); @@ -279,6 +280,14 @@ void IPARPi::setMode(const CameraSensorInfo &sensorInfo) * the line length in pixels and the pixel rate. */ mode_.line_length = 1e9 * sensorInfo.lineLength / sensorInfo.pixelRate; + + /* + * Set the vertical blanking (frame duration) limits for the mode to + * ensure exposure and framerate calculations are clipped appropriately. + */ + const auto itVblank = sensorCtrls_.find(V4L2_CID_VBLANK); + mode_.vblank_min = itVblank->second.min().get(); + mode_.vblank_max = itVblank->second.max().get(); } void IPARPi::configure(const CameraSensorInfo &sensorInfo, @@ -384,8 +393,8 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo, controller_.Initialise(); controllerInit_ = true; - minFrameDuration_ = defaultMinFrameDuration; - maxFrameDuration_ = defaultMaxFrameDuration; + /* Supply initial values for frame durations. */ + applyFrameDurations(defaultMinFrameDuration, defaultMaxFrameDuration); /* Supply initial values for gain and exposure. */ ControlList ctrls(sensorCtrls_); @@ -819,20 +828,7 @@ void IPARPi::queueRequest(const ControlList &controls) case controls::FRAME_DURATIONS: { auto frameDurations = ctrl.second.get>(); - - /* This will be applied once AGC recalculations occur. */ - minFrameDuration_ = frameDurations[0] ? frameDurations[0] : defaultMinFrameDuration; - maxFrameDuration_ = frameDurations[1] ? frameDurations[1] : defaultMaxFrameDuration; - maxFrameDuration_ = std::max(maxFrameDuration_, minFrameDuration_); - - /* - * \todo The values returned in the metadata below must be - * correctly clipped by what the sensor mode supports and - * what the AGC exposure mode or manual shutter speed limits - */ - libcameraMetadata_.set(controls::FrameDurations, - { static_cast(minFrameDuration_), - static_cast(maxFrameDuration_) }); + applyFrameDurations(frameDurations[0], frameDurations[1]); break; } @@ -991,6 +987,29 @@ void IPARPi::applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls) static_cast(awbStatus->gain_b * 1000)); } +void IPARPi::applyFrameDurations(double min, double max) +{ + const double minSensorFrameDuration = 1e-3 * (mode_.vblank_min + mode_.height) * + mode_.line_length; + const double maxSensorFrameDuration = 1e-3 * (mode_.vblank_max + mode_.height) * + mode_.line_length; + /* + * This will only be applied once AGC recalculations occur. + * The values may be clamped based on the sensor mode capabilities as well. + */ + minFrameDuration_ = min ? min : defaultMaxFrameDuration; + maxFrameDuration_ = max ? max : defaultMinFrameDuration; + minFrameDuration_ = std::clamp(minFrameDuration_, + minSensorFrameDuration, maxSensorFrameDuration); + maxFrameDuration_ = std::clamp(maxFrameDuration_, + minSensorFrameDuration, maxSensorFrameDuration); + + /* Return the validated limits out though metadata. */ + libcameraMetadata_.set(controls::FrameDurations, + { static_cast(minFrameDuration_), + static_cast(maxFrameDuration_) }); +} + void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls) { int32_t gainCode = helper_->GainCode(agcStatus->analogue_gain); From patchwork Thu Jan 21 11:58:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 10925 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 4286AC0F2A for ; Thu, 21 Jan 2021 11:59:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0CE84681F4; Thu, 21 Jan 2021 12:59:00 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="r+cR7WJD"; dkim-atps=neutral Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 344D8681ED for ; Thu, 21 Jan 2021 12:58:57 +0100 (CET) Received: by mail-wr1-x42c.google.com with SMTP id a1so1458022wrq.6 for ; Thu, 21 Jan 2021 03:58:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=vcbJR/GzM1Wv9CIUg93uXumJ7m5L8+WjsRCxsYGlzdA=; b=r+cR7WJDRzFp0Qf3bbNrWxHyXfd/0Pjo/yBQ8BFoP+MsdloFGGo+EwJQKmN8so1GkP HSko52aBqu3hzZtQ/O7zW7Qd6wKxi61dyr/+4hq4exKFOJxyJdIw0EebHDSm3oL0gHpD 0Hjtsl9SyaCk4xpWYwNEUChtn7XNVp3KtJW0XQ6J3uVAKKRfScLOASteEsytQCN/W+3k c4nRzLQ0ov+ieDm2WJ0vY2RWVbHIc7ipueB+oSP4ef3iuumLLHsjVMk+mMgcJL/Q5u+e OkhnGVrN5YO12a+Uv4xOnt57eH71/Xj14FTj047n+yo+zjyMmDGD63fdUqAIb6xMBInV rNRw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=vcbJR/GzM1Wv9CIUg93uXumJ7m5L8+WjsRCxsYGlzdA=; b=Ft9+Pl8u74Z+IUPM5FiVBpsZNNaKYSyeA6QbUM02VaRl9fIjxiv/3Xy1yOLMrt2jLv wL61di4opCodtCjxBhTjURx2QPtK9J3A8NtkYToo9bgQ9IsJAQHGRbI1uLvrYu0OHW8w 4uIUWysgl4gS+a//1wRF6H8apEK8Kjp294h/N/x37wNG34+AjOcsIh8lEtucJY1pkRaL Djc0RQpLklVoTGd1i1ZMR3MBoHLOPP51pQxN5lLBhyb2PHcMPKnLK+A0r2xMNUjT5bRJ FtYrC4Re4trisjJH58pFV8Nejc8i6gOzMIWpm0qR32vGh0Cg6qE3I7AHwm8P8Urkbx/d 9QfA== X-Gm-Message-State: AOAM530urbCI0h8aMKM2hwHuQjL2z+coqS7xbeFo/JUXAe4VBgFk2Mdz jX8H2wiTqVEicA3Aqy1epss5YgL+ONULPA== X-Google-Smtp-Source: ABdhPJxidI9RVQgXoqisi5lUfoeT23hZL95LU7tfnbKO/wCIVLuN619mtBCGfJiPvRVR28wfNz99KQ== X-Received: by 2002:a5d:4a11:: with SMTP id m17mr5881838wrq.39.1611230336505; Thu, 21 Jan 2021 03:58:56 -0800 (PST) Received: from naushir-VirtualBox.patuck.local ([88.97.76.4]) by smtp.gmail.com with ESMTPSA id h13sm8044930wrm.28.2021.01.21.03.58.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Jan 2021 03:58:55 -0800 (PST) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Thu, 21 Jan 2021 11:58:48 +0000 Message-Id: <20210121115849.682130-4-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210121115849.682130-1-naush@raspberrypi.com> References: <20210121115849.682130-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/4] ipa: raspberrypi: Pass the maximum allowable shutter speed into the AGC 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" In order to provide an optimal split between shutter speed and gain, the AGC must know the maximum allowable shutter speed, as limited by the maximum frame duration (either application provided or the default). Add a new API function, SetMaxShutter, to the AgcAlgorihtm class. The IPA provides the the maximum shutter speed for AGC calculations. This applies to both the manual and auto AGC modes. Signed-off-by: Naushir Patuck Reviewed-by: David Plowman --- .../raspberrypi/controller/agc_algorithm.hpp | 1 + src/ipa/raspberrypi/controller/rpi/agc.cpp | 49 +++++++++++++------ src/ipa/raspberrypi/controller/rpi/agc.hpp | 2 + src/ipa/raspberrypi/raspberrypi.cpp | 12 +++++ 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/ipa/raspberrypi/controller/agc_algorithm.hpp b/src/ipa/raspberrypi/controller/agc_algorithm.hpp index 981f1de2f0e4..f97deb0fca59 100644 --- a/src/ipa/raspberrypi/controller/agc_algorithm.hpp +++ b/src/ipa/raspberrypi/controller/agc_algorithm.hpp @@ -19,6 +19,7 @@ public: virtual void SetEv(double ev) = 0; virtual void SetFlickerPeriod(double flicker_period) = 0; virtual void SetFixedShutter(double fixed_shutter) = 0; // microseconds + virtual void SetMaxShutter(double max_shutter) = 0; // microseconds virtual void SetFixedAnalogueGain(double fixed_analogue_gain) = 0; virtual void SetMeteringMode(std::string const &metering_mode_name) = 0; virtual void SetExposureMode(std::string const &exposure_mode_name) = 0; diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp index eddd1684da12..937bb70ece67 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.cpp +++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp @@ -157,7 +157,7 @@ Agc::Agc(Controller *controller) frame_count_(0), lock_count_(0), last_target_exposure_(0.0), ev_(1.0), flicker_period_(0.0), - fixed_shutter_(0), fixed_analogue_gain_(0.0) + max_shutter_(0), fixed_shutter_(0), fixed_analogue_gain_(0.0) { memset(&awb_, 0, sizeof(awb_)); // Setting status_.total_exposure_value_ to zero initially tells us @@ -227,11 +227,23 @@ void Agc::SetFlickerPeriod(double flicker_period) flicker_period_ = flicker_period; } +static double clip_shutter(double shutter, double max_shutter) +{ + if (max_shutter) + shutter = std::min(shutter, max_shutter); + return shutter; +} + +void Agc::SetMaxShutter(double max_shutter) +{ + max_shutter_ = max_shutter; +} + void Agc::SetFixedShutter(double fixed_shutter) { fixed_shutter_ = fixed_shutter; // Set this in case someone calls Pause() straight after. - status_.shutter_time = fixed_shutter; + status_.shutter_time = clip_shutter(fixed_shutter_, max_shutter_); } void Agc::SetFixedAnalogueGain(double fixed_analogue_gain) @@ -261,7 +273,8 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode, { housekeepConfig(); - if (fixed_shutter_ != 0.0 && fixed_analogue_gain_ != 0.0) { + double fixed_shutter = clip_shutter(fixed_shutter_, max_shutter_); + if (fixed_shutter != 0.0 && fixed_analogue_gain_ != 0.0) { // We're going to reset the algorithm here with these fixed values. fetchAwbStatus(metadata); @@ -269,14 +282,14 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode, ASSERT(min_colour_gain != 0.0); // This is the equivalent of computeTargetExposure and applyDigitalGain. - target_.total_exposure_no_dg = fixed_shutter_ * fixed_analogue_gain_; + target_.total_exposure_no_dg = fixed_shutter * fixed_analogue_gain_; target_.total_exposure = target_.total_exposure_no_dg / min_colour_gain; // Equivalent of filterExposure. This resets any "history". filtered_ = target_; // Equivalent of divideUpExposure. - filtered_.shutter = fixed_shutter_; + filtered_.shutter = fixed_shutter; filtered_.analogue_gain = fixed_analogue_gain_; } else if (status_.total_exposure_value) { // On a mode switch, it's possible the exposure profile could change, @@ -290,7 +303,7 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode, // for any that weren't set. // Equivalent of divideUpExposure. - filtered_.shutter = fixed_shutter_ ? fixed_shutter_ : config_.default_exposure_time; + filtered_.shutter = fixed_shutter ? fixed_shutter : config_.default_exposure_time; filtered_.analogue_gain = fixed_analogue_gain_ ? fixed_analogue_gain_ : config_.default_analogue_gain; } @@ -403,7 +416,8 @@ void Agc::housekeepConfig() { // First fetch all the up-to-date settings, so no one else has to do it. status_.ev = ev_; - status_.fixed_shutter = fixed_shutter_; + double fixed_shutter = clip_shutter(fixed_shutter_, max_shutter_); + status_.fixed_shutter = fixed_shutter; status_.fixed_analogue_gain = fixed_analogue_gain_; status_.flicker_period = flicker_period_; LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixed_shutter " @@ -582,13 +596,15 @@ void Agc::computeTargetExposure(double gain) target_.total_exposure = current_.total_exposure_no_dg * gain; // The final target exposure is also limited to what the exposure // mode allows. + double max_shutter = status_.fixed_shutter != 0.0 + ? status_.fixed_shutter + : exposure_mode_->shutter.back(); + max_shutter = clip_shutter(max_shutter, max_shutter_); double max_total_exposure = - (status_.fixed_shutter != 0.0 - ? status_.fixed_shutter - : exposure_mode_->shutter.back()) * + max_shutter * (status_.fixed_analogue_gain != 0.0 - ? status_.fixed_analogue_gain - : exposure_mode_->gain.back()); + ? status_.fixed_analogue_gain + : exposure_mode_->gain.back()); target_.total_exposure = std::min(target_.total_exposure, max_total_exposure); } @@ -671,6 +687,7 @@ void Agc::divideUpExposure() shutter_time = status_.fixed_shutter != 0.0 ? status_.fixed_shutter : exposure_mode_->shutter[0]; + shutter_time = clip_shutter(shutter_time, max_shutter_); analogue_gain = status_.fixed_analogue_gain != 0.0 ? status_.fixed_analogue_gain : exposure_mode_->gain[0]; @@ -678,14 +695,16 @@ void Agc::divideUpExposure() for (unsigned int stage = 1; stage < exposure_mode_->gain.size(); stage++) { if (status_.fixed_shutter == 0.0) { - if (exposure_mode_->shutter[stage] * - analogue_gain >= + double stage_shutter = + clip_shutter(exposure_mode_->shutter[stage], + max_shutter_); + if (stage_shutter * analogue_gain >= exposure_value) { shutter_time = exposure_value / analogue_gain; break; } - shutter_time = exposure_mode_->shutter[stage]; + shutter_time = stage_shutter; } if (status_.fixed_analogue_gain == 0.0) { if (exposure_mode_->gain[stage] * diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp index 05c334e4a1de..2ce3b1a1700a 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.hpp +++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp @@ -78,6 +78,7 @@ public: unsigned int GetConvergenceFrames() const override; void SetEv(double ev) override; void SetFlickerPeriod(double flicker_period) override; + void SetMaxShutter(double max_shutter) override; // microseconds void SetFixedShutter(double fixed_shutter) override; // microseconds void SetFixedAnalogueGain(double fixed_analogue_gain) override; void SetMeteringMode(std::string const &metering_mode_name) override; @@ -126,6 +127,7 @@ private: std::string constraint_mode_name_; double ev_; double flicker_period_; + double max_shutter_; double fixed_shutter_; double fixed_analogue_gain_; }; diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp index 9e6e030c4997..2b71efc63f10 100644 --- a/src/ipa/raspberrypi/raspberrypi.cpp +++ b/src/ipa/raspberrypi/raspberrypi.cpp @@ -1008,6 +1008,18 @@ void IPARPi::applyFrameDurations(double min, double max) libcameraMetadata_.set(controls::FrameDurations, { static_cast(minFrameDuration_), static_cast(maxFrameDuration_) }); + + /* + * Calculate the maximum exposure time possible for the AGC to use. + * GetVBlanking() will update maxShutter with the largest exposure + * value possible. + */ + double maxShutter = std::numeric_limits::max(); + helper_->GetVBlanking(maxShutter, minFrameDuration_, maxFrameDuration_); + + RPiController::AgcAlgorithm *agc = dynamic_cast( + controller_.GetAlgorithm("agc")); + agc->SetMaxShutter(maxShutter); } void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls) From patchwork Thu Jan 21 11:58:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 10926 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 9F29BC0F2B for ; Thu, 21 Jan 2021 11:59:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 665AA681EE; Thu, 21 Jan 2021 12:59:00 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="bb8/j4pH"; dkim-atps=neutral Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 64B70681F3 for ; Thu, 21 Jan 2021 12:58:58 +0100 (CET) Received: by mail-wr1-x435.google.com with SMTP id a9so1452059wrt.5 for ; Thu, 21 Jan 2021 03:58:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=wbMF+KvzLd6qSkStJhzEh/KUO8Z01x1gWbfkhwWRLzo=; b=bb8/j4pHC+simkj0oyESZxsCbuwNixKXgnt9unOWxq9sj53DvV2DZ4zfM6MVuflXek NZaag/rZ9IAQfwRBBOT2UKJ3JJRIbooKCZiwsm322rbPoaUJWhy4o2Psp7k1YShOzoiF C4TqvQctkwayEme41NrMTdubhgjpqf2nomaWY/jQzCAMrnzuhrbQEU71DJOEHnOzEelP O+blKOIafqCxSGxTBvgGBsriWl1FjRJm0qR/l+Wp0AVwQsMSzDbfS0zxiEo3CERlksjD FCFex0qWbfdpTIgN9sGOmaIbfKIBSyB7kXWpDE1uIlB/GPjEiksIPPbWvry8ZWphSr4s Uk3A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wbMF+KvzLd6qSkStJhzEh/KUO8Z01x1gWbfkhwWRLzo=; b=FHLicJzG9IJQEkdgoU7s2c5FXpDPp3TNknpNM+Io+lpbpZ/93VC8mEQn9hsSEqnz0M 2/HVaIJ4eR52Kq1/dRF6M0kzVLz8P5Vnao2eP6VIrydxNnz8K3Woi8Bn7sUcZ9tSPEvD cv6nN0EaYEjlKlf991//Bfwo5eE0He+U2yaOZ7iVwzyxbZVFAKbnLo1xnD7G3XR/7tlp FXj8BkuY2L4k7O2xGFep6DbrTVrrIGHrOfjDNfo91oUXBtlBPjRq3p2acsjqLYrSQImq 2adcgJddmbypCqfW5LvQI4RCr/bZzCoc09hUzxPccesSQNQmCcxM0RBdYx58WKGaBGO7 8OXQ== X-Gm-Message-State: AOAM531i2ioV/bZ5dZu7Z+L8DnQ3LDKeeFp7g3afhp9bLT7izRDbL4Xa RO5miBFkn4sxHrncTxlHThNpgzK4xgGong== X-Google-Smtp-Source: ABdhPJxeFHal94kBYe1In4wHhNIxCJlINQhRM+l2fqKfY20hNDPuoxB4Qj8j9QzMmQ2zliixMplXFA== X-Received: by 2002:a05:6000:1043:: with SMTP id c3mr13139844wrx.140.1611230337764; Thu, 21 Jan 2021 03:58:57 -0800 (PST) Received: from naushir-VirtualBox.patuck.local ([88.97.76.4]) by smtp.gmail.com with ESMTPSA id h13sm8044930wrm.28.2021.01.21.03.58.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Jan 2021 03:58:56 -0800 (PST) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Thu, 21 Jan 2021 11:58:49 +0000 Message-Id: <20210121115849.682130-5-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210121115849.682130-1-naush@raspberrypi.com> References: <20210121115849.682130-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 4/4] pipeline: raspberrypi: Add notion of immediate write to StaggeredCtrl 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" If an exposure time change adjusts the vblanking limits, and we write both VBLANK and EXPOSURE controls as a set, the latter may fail if the value is outside of the limits calculated by the old VBLANK value. This is a limitation in V4L2 and cannot be fixed by writing VBLANK before EXPOSURE. The workaround here is to have the StaggeredCtrl mark the VBLANK control as "immediate write", which then write VBLANK separately from (and ahead of) any other controls. This way, the sensor driver will update the EXPOSURE control with new limits before the new values is presented, and will thus be seen as valid. StaggeredCtrl is due to be deprecated and replaced by DelayedCtrl, so this change serves more a working proof-of-concept on the workaround, and not much care has been taken to provide a nice new API for applying this immediate write flag to the control. A similar workaround must be available to DelayedCtrl eventually. Signed-off-by: Naushir Patuck --- src/ipa/raspberrypi/raspberrypi.cpp | 5 ++- .../pipeline/raspberrypi/raspberrypi.cpp | 11 ++++-- .../pipeline/raspberrypi/staggered_ctrl.cpp | 39 ++++++++++++++----- .../pipeline/raspberrypi/staggered_ctrl.h | 3 +- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp index 2b71efc63f10..c6a1e8027284 100644 --- a/src/ipa/raspberrypi/raspberrypi.cpp +++ b/src/ipa/raspberrypi/raspberrypi.cpp @@ -1040,8 +1040,9 @@ void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls) /* * Due to the behavior of V4L2, the current value of VBLANK could clip the - * exposure time without us knowing. The next time though this function should - * clip exposure correctly. + * exposure time without us knowing. We get around this by ensuring the + * staggered write component submits VBLANK separately from, and before the + * EXPOSURE control. */ ctrls.set(V4L2_CID_VBLANK, vblanking); ctrls.set(V4L2_CID_EXPOSURE, exposureLines); diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 524cc960dd37..1485999ad2a0 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -1229,12 +1229,17 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config) /* * Setup our staggered control writer with the sensor default * gain and exposure delays. + * + * VBLANK must be flagged as "immediate write" to allow it to + * be set immediately instead of being batched with all other + * controls. This is needed so that any update to the EXPOSURE + * control will be validated based on the new VBLANK control value. */ if (!staggeredCtrl_) { staggeredCtrl_.init(unicam_[Unicam::Image].dev(), - { { V4L2_CID_ANALOGUE_GAIN, result.data[resultIdx++] }, - { V4L2_CID_EXPOSURE, result.data[resultIdx++] }, - { V4L2_CID_VBLANK, result.data[resultIdx++] } }); + { { V4L2_CID_ANALOGUE_GAIN, result.data[resultIdx++], false }, + { V4L2_CID_EXPOSURE, result.data[resultIdx++], false }, + { V4L2_CID_VBLANK, result.data[resultIdx++], true } }); sensorMetadata_ = result.data[resultIdx++]; } } diff --git a/src/libcamera/pipeline/raspberrypi/staggered_ctrl.cpp b/src/libcamera/pipeline/raspberrypi/staggered_ctrl.cpp index 62605c0fceee..07f8c95d4f2c 100644 --- a/src/libcamera/pipeline/raspberrypi/staggered_ctrl.cpp +++ b/src/libcamera/pipeline/raspberrypi/staggered_ctrl.cpp @@ -22,21 +22,29 @@ LOG_DEFINE_CATEGORY(RPI_S_W) namespace RPi { void StaggeredCtrl::init(V4L2VideoDevice *dev, - std::initializer_list> delayList) + std::initializer_list> delayList) { std::lock_guard lock(lock_); dev_ = dev; - delay_ = delayList; + delay_.clear(); ctrl_.clear(); - /* Find the largest delay across all controls. */ maxDelay_ = 0; - for (auto const &p : delay_) { + for (auto const &c : delayList) { + uint32_t id = std::get<0>(c); + uint8_t delay = std::get<1>(c); + bool immediateWrite = std::get<2>(c); + + delay_[id] = delay; + immediateWrite_[id] = immediateWrite; + LOG(RPI_S_W, Info) << "Init ctrl " - << utils::hex(p.first) << " with delay " - << static_cast(p.second); - maxDelay_ = std::max(maxDelay_, p.second); + << utils::hex(id) << " with delay " + << static_cast(delay); + + /* Find the largest delay across all controls. */ + maxDelay_ = std::max(maxDelay_, delay); } init_ = true; @@ -121,8 +129,21 @@ int StaggeredCtrl::write() int index = std::max(0, setCount_ - delayDiff); if (p.second[index].updated) { - /* We need to write this value out. */ - controls.set(p.first, p.second[index].value); + if (immediateWrite_[p.first]) { + /* + * This control must be written now, it could + * affect validity of the other controls. + */ + ControlList immediate(dev_->controls()); + immediate.set(p.first, p.second[index].value); + dev_->setControls(&immediate); + } else { + /* + * Batch up the list of controls and write them + * at the end of the function. + */ + controls.set(p.first, p.second[index].value); + } p.second[index].updated = false; LOG(RPI_S_W, Debug) << "Writing ctrl " << utils::hex(p.first) << " to " diff --git a/src/libcamera/pipeline/raspberrypi/staggered_ctrl.h b/src/libcamera/pipeline/raspberrypi/staggered_ctrl.h index 382fa31a6853..7c920c3a13c7 100644 --- a/src/libcamera/pipeline/raspberrypi/staggered_ctrl.h +++ b/src/libcamera/pipeline/raspberrypi/staggered_ctrl.h @@ -34,7 +34,7 @@ public: } void init(V4L2VideoDevice *dev, - std::initializer_list> delayList); + std::initializer_list> delayList); void reset(); void get(std::unordered_map &ctrl, uint8_t offset = 0); @@ -85,6 +85,7 @@ private: uint8_t maxDelay_; V4L2VideoDevice *dev_; std::unordered_map delay_; + std::unordered_map immediateWrite_; std::unordered_map ctrl_; std::mutex lock_; };