From patchwork Mon Feb 22 11:32:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 11363 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 95C11BD1F1 for ; Mon, 22 Feb 2021 11:32:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 241EE68A04; Mon, 22 Feb 2021 12:32:09 +0100 (CET) Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5450D637DA for ; Mon, 22 Feb 2021 12:32:07 +0100 (CET) X-Originating-IP: 93.34.118.233 Received: from uno.lan (93-34-118-233.ip49.fastwebnet.it [93.34.118.233]) (Authenticated sender: jacopo@jmondi.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 70DB360002; Mon, 22 Feb 2021 11:32:06 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Mon, 22 Feb 2021 12:32:27 +0100 Message-Id: <20210222113227.395737-1-jacopo@jmondi.org> X-Mailer: git-send-email 2.30.0 MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5] libcamera: ipu3: Add rotation to ipu3 pipeline 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" From: Fabian Wüthrich Use the same transformation logic as in the raspberry pipeline to implement rotations in the ipu3 pipeline. Tested on a Surface Book 2 with an experimental driver for OV5693. Signed-off-by: Fabian Wüthrich Reviewed-by: Kieran Bingham Reviewed-by: Jacopo Mondi Signed-off-by: Jacopo Mondi Acked-by: Fabian Wüthrich --- I have re-based and re-worked this slightly - Rebased on master - Remove snake_case variables - Move H/V flip setting from the end of configure() to just before the part where bail out if the request contains only raw streams, so that transform can be applied on RAW images as well - Minor style changes such as breaking lines more often Fabian, could you re-ack this, and maybe if you have a setup to do so re-test ? I'll push it with your ack! Thanks j --- src/libcamera/pipeline/ipu3/ipu3.cpp | 87 +++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) -- 2.30.0 diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index b8a655ce0b68..0561a4610007 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,9 @@ public: uint32_t exposureTime_; Rectangle cropRegion_; + bool supportsFlips_; + Transform rotationTransform_; + std::unique_ptr delayedCtrls_; IPU3Frames frameInfos_; @@ -95,6 +99,9 @@ public: const StreamConfiguration &cio2Format() const { return cio2Configuration_; } const ImgUDevice::PipeConfig imguConfig() const { return pipeConfig_; } + /* Cache the combinedTransform_ that will be applied to the sensor */ + Transform combinedTransform_; + private: /* * The IPU3CameraData instance is guaranteed to be valid as long as the @@ -167,11 +174,49 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate() if (config_.empty()) return Invalid; - if (transform != Transform::Identity) { - transform = Transform::Identity; + Transform combined = transform * data_->rotationTransform_; + + /* + * We combine the platform and user transform, but must "adjust away" + * any combined result that includes a transposition, as we can't do + * those. In this case, flipping only the transpose bit is helpful to + * applications - they either get the transform they requested, or have + * to do a simple transpose themselves (they don't have to worry about + * the other possible cases). + */ + if (!!(combined & Transform::Transpose)) { + /* + * Flipping the transpose bit in "transform" flips it in the + * combined result too (as it's the last thing that happens), + * which is of course clearing it. + */ + transform ^= Transform::Transpose; + combined &= ~Transform::Transpose; + status = Adjusted; + } + + /* + * We also check if the sensor doesn't do h/vflips at all, in which + * case we clear them, and the application will have to do everything. + */ + if (!data_->supportsFlips_ && !!combined) { + /* + * If the sensor can do no transforms, then combined must be + * changed to the identity. The only user transform that gives + * rise to this is the inverse of the rotation. (Recall that + * combined = transform * rotationTransform.) + */ + transform = -data_->rotationTransform_; + combined = Transform::Identity; status = Adjusted; } + /* + * Store the final combined transform that configure() will need to + * apply to the sensor to save us working it out again. + */ + combinedTransform_ = combined; + /* Cap the number of entries to the available streams. */ if (config_.size() > IPU3_MAX_STREAMS) { config_.resize(IPU3_MAX_STREAMS); @@ -503,6 +548,24 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) cio2->sensor()->sensorInfo(&sensorInfo); data->cropRegion_ = sensorInfo.analogCrop; + /* + * Configure the H/V flip controls based on the combination of + * the sensor and user transform. + */ + if (data->supportsFlips_) { + ControlList sensorCtrls(cio2->sensor()->controls()); + sensorCtrls.set(V4L2_CID_HFLIP, + static_cast(!!(config->combinedTransform_ + & Transform::HFlip))); + sensorCtrls.set(V4L2_CID_VFLIP, + static_cast(!!(config->combinedTransform_ + & Transform::VFlip))); + + ret = cio2->sensor()->setControls(&sensorCtrls); + if (ret) + return ret; + } + /* * If the ImgU gets configured, its driver seems to expect that * buffers will be queued to its outputs, as otherwise the next @@ -980,6 +1043,26 @@ int PipelineHandlerIPU3::registerCameras() data->cio2_.frameStart().connect(data->delayedCtrls_.get(), &DelayedControls::applyControls); + /* Convert the sensor rotation to a transformation */ + int32_t rotation = 0; + if (data->properties_.contains(properties::Rotation)) + rotation = data->properties_.get(properties::Rotation); + else + LOG(IPU3, Warning) << "Rotation control not exposed by " + << cio2->sensor()->id() + << ". Assume rotation 0"; + + bool success; + data->rotationTransform_ = transformFromRotation(rotation, &success); + if (!success) + LOG(IPU3, Warning) << "Invalid rotation of " << rotation + << " degrees: ignoring"; + + ControlList ctrls = cio2->sensor()->getControls({ V4L2_CID_HFLIP }); + if (!ctrls.empty()) + /* We assume it will support vflips too... */ + data->supportsFlips_ = true; + /** * \todo Dynamically assign ImgU and output devices to each * stream and camera; as of now, limit support to two cameras