[{"id":36467,"web_url":"https://patchwork.libcamera.org/comment/36467/","msgid":"<ztq7wavyughwzczn4rjvbck4rbwvtc7gltebhr2awws5mw2sug@mudaqbrbpheo>","date":"2025-10-25T13:41:01","subject":"Re: [PATCH v2 29/35] libcamera: rkisp1: Handle requested orientation\n\tusing dewarper","submitter":{"id":232,"url":"https://patchwork.libcamera.org/api/people/232/","name":"Umang Jain","email":"uajain@igalia.com"},"content":"On Thu, Oct 23, 2025 at 04:48:30PM +0200, Stefan Klug wrote:\n> When the dewarper is present it can handle arbitrary orientations\n> specified in the requested camera configuration. In that case handle all\n> transformations inside the dewarper (even if the sensor supports some of\n> them) because that makes it easier to handle coordinates for lens\n> dewarping inside the dewarper.\n> \n> This complicates the path selection a bit, as for transformations that\n> include a transpose, the format before the dewarper has swapped\n> width/height.\n> \n> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n\nOne question: I see you tied it to the CameraConfiguration::orientation,\nso that means the rotation (even via dewarper) will be static for the \nentire stream duration. I think that's what expected as per this patch?\n\nBut I think the dewarper also supports dynamic rotation as well? Are\ntheir any (future) plans to support that, as I am more interested if \nthere will be rotation related controls.\n\n> \n> ---\n> \n> Changes in v2:\n> \n> - Fix path validation for cases where a transpose is involved\n> ---\n>  src/libcamera/pipeline/rkisp1/rkisp1.cpp | 97 +++++++++++++++++-------\n>  1 file changed, 71 insertions(+), 26 deletions(-)\n> \n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> index 943f26ece974..eaf82d0f1097 100644\n> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> @@ -596,11 +596,6 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>  \t\tstatus = Adjusted;\n>  \t}\n>  \n> -\tOrientation requestedOrientation = orientation;\n> -\tcombinedTransform_ = data_->sensor_->computeTransform(&orientation);\n> -\tif (orientation != requestedOrientation)\n> -\t\tstatus = Adjusted;\n> -\n>  \t/*\n>  \t * Simultaneous capture of raw and processed streams isn't possible. If\n>  \t * there is any raw stream, cap the number of streams to one.\n> @@ -618,9 +613,24 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>  \t\t}\n>  \t}\n>  \n> +\t/*\n> +\t * If the dewarper supports orientation adjustments, apply that completely\n> +\t * there. Even if the sensor supports flips, it is beneficial to do that\n> +\t * in the dewarper so that lens dewarping happens on the unflipped image\n> +\t */\n> +\tbool transposeAfterIsp = false;\n>  \tbool useDewarper = false;\n> -\tif (data_->canUseDewarper_ && !isRaw)\n> +\tif (data_->canUseDewarper_ && !isRaw) {\n>  \t\tuseDewarper = true;\n> +\t\tcombinedTransform_ = orientation / data_->sensor_->mountingOrientation();\n> +\t\tif (!!(combinedTransform_ & Transform::Transpose))\n> +\t\t\ttransposeAfterIsp = true;\n> +\t} else {\n> +\t\tOrientation requestedOrientation = orientation;\n> +\t\tcombinedTransform_ = data_->sensor_->computeTransform(&orientation);\n> +\t\tif (orientation != requestedOrientation)\n> +\t\t\tstatus = Adjusted;\n> +\t}\n>  \n>  \t/*\n>  \t * If there are more than one stream in the configuration figure out the\n> @@ -636,12 +646,18 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>  \n>  \t/*\n>  \t * Validate the configuration against the desired path and, if the\n> -\t * platform supports it, the dewarper.\n> +\t * platform supports it, the dewarper. While iterating over the\n> +\t * configurations collect the smallest common sensor format.\n>  \t */\n> +\tSize accumulatedSensorSize;\n>  \tauto validateConfig = [&](StreamConfiguration &cfg, RkISP1Path *path,\n>  \t\t\t\t  Stream *stream, Status expectedStatus) {\n>  \t\tStreamConfiguration tryCfg = cfg;\n>  \n> +\t\t/* Need to validate the path before the transpose */\n> +\t\tif (transposeAfterIsp)\n> +\t\t\ttryCfg.size.transpose();\n> +\n>  \t\tStatus ret = path->validate(sensor, sensorConfig, &tryCfg);\n>  \t\tif (ret == Invalid)\n>  \t\t\treturn false;\n> @@ -650,6 +666,8 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>  \t\t    (expectedStatus == Valid && ret == Adjusted))\n>  \t\t\treturn false;\n>  \n> +\t\tSize sensorSize = tryCfg.size;\n> +\n>  \t\tif (useDewarper) {\n>  \t\t\t/*\n>  \t\t\t * The dewarper output is independent of the ISP path.\n> @@ -672,6 +690,8 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>  \n>  \t\tcfg = tryCfg;\n>  \t\tcfg.setStream(stream);\n> +\n> +\t\taccumulatedSensorSize = std::max(accumulatedSensorSize, sensorSize);\n>  \t\treturn true;\n>  \t};\n>  \n> @@ -722,13 +742,6 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>  \t\treturn Invalid;\n>  \t}\n>  \n> -\t/* Select the sensor format. */\n> -\tSize maxSize;\n> -\n> -\tfor (const StreamConfiguration &cfg : config_) {\n> -\t\tmaxSize = std::max(maxSize, cfg.size);\n> -\t}\n> -\n>  \tstd::vector<unsigned int> mbusCodes;\n>  \n>  \tif (isRaw) {\n> @@ -739,7 +752,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>  \t\t\t       [](const auto &value) { return value.second; });\n>  \t}\n>  \n> -\tsensorFormat_ = sensor->getFormat(mbusCodes, maxSize,\n> +\tsensorFormat_ = sensor->getFormat(mbusCodes, accumulatedSensorSize,\n>  \t\t\t\t\t  mainPath->maxResolution());\n>  \n>  \tif (sensorFormat_.size.isNull())\n> @@ -774,6 +787,22 @@ PipelineHandlerRkISP1::generateConfiguration(Camera *camera,\n>  \tif (roles.empty())\n>  \t\treturn config;\n>  \n> +\tTransform transform = Transform::Identity;\n> +\tSize previewSize = kRkISP1PreviewSize;\n> +\tbool transposeAfterIsp = false;\n> +\tif (data->canUseDewarper_) {\n> +\t\ttransform = Orientation::Rotate0 / data->sensor_->mountingOrientation();\n> +\t\tif (!!(transform & Transform::Transpose))\n> +\t\t\ttransposeAfterIsp = true;\n> +\t}\n> +\n> +\t/*\n> +\t * In case of a transpose transform we need to create a path for the\n> +\t * transposed size.\n> +\t */\n> +\tif (transposeAfterIsp)\n> +\t\tpreviewSize.transpose();\n> +\n>  \t/*\n>  \t * As the ISP can't output different color spaces for the main and self\n>  \t * path, pick a sensible default color space based on the role of the\n> @@ -802,7 +831,7 @@ PipelineHandlerRkISP1::generateConfiguration(Camera *camera,\n>  \t\t\tif (!colorSpace)\n>  \t\t\t\tcolorSpace = ColorSpace::Sycc;\n>  \n> -\t\t\tsize = kRkISP1PreviewSize;\n> +\t\t\tsize = previewSize;\n>  \t\t\tbreak;\n>  \n>  \t\tcase StreamRole::VideoRecording:\n> @@ -810,7 +839,7 @@ PipelineHandlerRkISP1::generateConfiguration(Camera *camera,\n>  \t\t\tif (!colorSpace)\n>  \t\t\t\tcolorSpace = ColorSpace::Rec709;\n>  \n> -\t\t\tsize = kRkISP1PreviewSize;\n> +\t\t\tsize = previewSize;\n>  \t\t\tbreak;\n>  \n>  \t\tcase StreamRole::Raw:\n> @@ -852,6 +881,9 @@ PipelineHandlerRkISP1::generateConfiguration(Camera *camera,\n>  \t\tif (!cfg.pixelFormat.isValid())\n>  \t\t\treturn nullptr;\n>  \n> +\t\tif (transposeAfterIsp && role != StreamRole::Raw)\n> +\t\t\tcfg.size.transpose();\n> +\n>  \t\tcfg.colorSpace = colorSpace;\n>  \t\tcfg.bufferCount = kRkISP1MinBufferCount;\n>  \t\tconfig->addConfiguration(cfg);\n> @@ -874,6 +906,19 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n>  \tif (ret)\n>  \t\treturn ret;\n>  \n> +\tconst PixelFormat &streamFormat = config->at(0).pixelFormat;\n> +\tconst PixelFormatInfo &info = PixelFormatInfo::info(streamFormat);\n> +\tisRaw_ = info.colourEncoding == PixelFormatInfo::ColourEncodingRAW;\n> +\tdata->usesDewarper_ = data->canUseDewarper_ && !isRaw_;\n> +\n> +\tTransform transform = config->combinedTransform();\n> +\tbool transposeAfterIsp = false;\n> +\tif (data->usesDewarper_) {\n> +\t\tif (!!(transform & Transform::Transpose))\n> +\t\t\ttransposeAfterIsp = true;\n> +\t\ttransform = Transform::Identity;\n> +\t}\n> +\n>  \t/*\n>  \t * Configure the format on the sensor output and propagate it through\n>  \t * the pipeline.\n> @@ -883,10 +928,10 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n>  \n>  \tif (config->sensorConfig)\n>  \t\tret = sensor->applyConfiguration(*config->sensorConfig,\n> -\t\t\t\t\t\t config->combinedTransform(),\n> +\t\t\t\t\t\t transform,\n>  \t\t\t\t\t\t &format);\n>  \telse\n> -\t\tret = sensor->setFormat(&format, config->combinedTransform());\n> +\t\tret = sensor->setFormat(&format, transform);\n>  \n>  \tif (ret < 0)\n>  \t\treturn ret;\n> @@ -913,10 +958,6 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n>  \t\t<< \" crop \" << inputCrop;\n>  \n>  \tRectangle outputCrop = inputCrop;\n> -\tconst PixelFormat &streamFormat = config->at(0).pixelFormat;\n> -\tconst PixelFormatInfo &info = PixelFormatInfo::info(streamFormat);\n> -\tisRaw_ = info.colourEncoding == PixelFormatInfo::ColourEncodingRAW;\n> -\tdata->usesDewarper_ = dewarper_ && !isRaw_;\n>  \n>  \t/* YUYV8_2X8 is required on the ISP source path pad for YUV output. */\n>  \tif (!isRaw_)\n> @@ -1008,15 +1049,19 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n>  \t\t\t\t\tinputCrop, sensorInfo.analogCrop);\n>  \t\t\t\tauto &vertexMap = dewarper_->vertexMap(cfg.stream());\n>  \t\t\t\tvertexMap.setSensorCrop(sensorCrop);\n> +\t\t\t\tvertexMap.setTransform(config->combinedTransform());\n>  \t\t\t\tdata->properties_.set(properties::ScalerCropMaximum, sensorCrop);\n>  \n>  \t\t\t\t/*\n>  \t\t\t\t * Apply a default sensor crop that keeps the\n>  \t\t\t\t * aspect ratio.\n>  \t\t\t\t */\n> -\t\t\t\tSize crop = format.size.boundedToAspectRatio(cfg.size);\n> -\t\t\t\tvertexMap.setScalerCrop(crop.centeredTo(\n> -\t\t\t\t\tRectangle(format.size).center()));\n> +\t\t\t\tSize size = cfg.size;\n> +\t\t\t\tif (transposeAfterIsp)\n> +\t\t\t\t\tsize.transpose();\n> +\t\t\t\tsize = sensorCrop.size().boundedToAspectRatio(size);\n> +\t\t\t\tvertexMap.setScalerCrop(\n> +\t\t\t\t\tsize.centeredTo(sensorCrop.center()));\n>  \t\t\t}\n>  \n>  \t\t\tret = mainPath_.configure(ispCfg, format);\n> -- \n> 2.48.1\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id ECB20BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 25 Oct 2025 13:40:35 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6E1DB606B1;\n\tSat, 25 Oct 2025 15:40:34 +0200 (CEST)","from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 12A7A60697\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 25 Oct 2025 15:40:33 +0200 (CEST)","from amazon1-vf-gw.lnd.cw.net ([195.89.103.118] helo=uajain)\n\tby fanzine2.igalia.com with esmtpsa \n\t(Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)\n\t(Exim) id 1vCeVU-00F7M0-Ad; Sat, 25 Oct 2025 15:40:32 +0200"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=igalia.com header.i=@igalia.com\n\theader.b=\"aA9/RnXp\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com;\n\ts=20170329;\n\th=In-Reply-To:Content-Type:MIME-Version:References:Message-ID:\n\tSubject:Cc:To:From:Date:Sender:Reply-To:Content-Transfer-Encoding:Content-ID:\n\tContent-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc\n\t:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe:\n\tList-Post:List-Owner:List-Archive;\n\tbh=TBGqo5cDCUtEhfZjgyqNiobgMPINbSlrsq1LYOEXv1o=;\n\tb=aA9/RnXp3vr+Am9YBLyAwu5kKM\n\tdslQbPs36bLztveWHVGkf9R6lXiG2S/Thh5bFC1G6QZtA1e9mWM4Hnpd5NyxavrUR0sFHCnQNhrv5\n\t92Ot3XSJ5VtyxzN4XfkmIbr87IvN+6OiuGMD7k07SialHiYcO0bK/t4HnUBBeQrG76kZhXEGjI4r8\n\tb4pf8R2Jr4yn4lxrW9CIby0vivbaquxFms1QoYW7A+0f9a8nreAVMayenydnfcLoHqz5M0xdsvFlG\n\tkDnKwMYZ1aEe8S1hZCoh3dElvZTolLVXGYoRTxlmQrCQocVYy6+rbA4yETV2yAeS4DwkpFFMTqWBx\n\tkVn1lbow==;","Date":"Sat, 25 Oct 2025 14:41:01 +0100","From":"Umang Jain <uajain@igalia.com>","To":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v2 29/35] libcamera: rkisp1: Handle requested orientation\n\tusing dewarper","Message-ID":"<ztq7wavyughwzczn4rjvbck4rbwvtc7gltebhr2awws5mw2sug@mudaqbrbpheo>","References":"<20251023144841.403689-1-stefan.klug@ideasonboard.com>\n\t<20251023144841.403689-30-stefan.klug@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20251023144841.403689-30-stefan.klug@ideasonboard.com>","User-Agent":"NeoMutt/20250905-dirty","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":36736,"web_url":"https://patchwork.libcamera.org/comment/36736/","msgid":"<176243757234.2116251.15219359896207623621@neptunite.rasen.tech>","date":"2025-11-06T13:59:32","subject":"Re: [PATCH v2 29/35] libcamera: rkisp1: Handle requested orientation\n\tusing dewarper","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Quoting Stefan Klug (2025-10-23 23:48:30)\n> When the dewarper is present it can handle arbitrary orientations\n> specified in the requested camera configuration. In that case handle all\n> transformations inside the dewarper (even if the sensor supports some of\n> them) because that makes it easier to handle coordinates for lens\n> dewarping inside the dewarper.\n> \n> This complicates the path selection a bit, as for transformations that\n> include a transpose, the format before the dewarper has swapped\n> width/height.\n> \n> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n> \n\nLooks good to me.\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n> ---\n> \n> Changes in v2:\n> \n> - Fix path validation for cases where a transpose is involved\n> ---\n>  src/libcamera/pipeline/rkisp1/rkisp1.cpp | 97 +++++++++++++++++-------\n>  1 file changed, 71 insertions(+), 26 deletions(-)\n> \n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> index 943f26ece974..eaf82d0f1097 100644\n> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> @@ -596,11 +596,6 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>                 status = Adjusted;\n>         }\n>  \n> -       Orientation requestedOrientation = orientation;\n> -       combinedTransform_ = data_->sensor_->computeTransform(&orientation);\n> -       if (orientation != requestedOrientation)\n> -               status = Adjusted;\n> -\n>         /*\n>          * Simultaneous capture of raw and processed streams isn't possible. If\n>          * there is any raw stream, cap the number of streams to one.\n> @@ -618,9 +613,24 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>                 }\n>         }\n>  \n> +       /*\n> +        * If the dewarper supports orientation adjustments, apply that completely\n> +        * there. Even if the sensor supports flips, it is beneficial to do that\n> +        * in the dewarper so that lens dewarping happens on the unflipped image\n> +        */\n> +       bool transposeAfterIsp = false;\n>         bool useDewarper = false;\n> -       if (data_->canUseDewarper_ && !isRaw)\n> +       if (data_->canUseDewarper_ && !isRaw) {\n>                 useDewarper = true;\n> +               combinedTransform_ = orientation / data_->sensor_->mountingOrientation();\n> +               if (!!(combinedTransform_ & Transform::Transpose))\n> +                       transposeAfterIsp = true;\n> +       } else {\n> +               Orientation requestedOrientation = orientation;\n> +               combinedTransform_ = data_->sensor_->computeTransform(&orientation);\n> +               if (orientation != requestedOrientation)\n> +                       status = Adjusted;\n> +       }\n>  \n>         /*\n>          * If there are more than one stream in the configuration figure out the\n> @@ -636,12 +646,18 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>  \n>         /*\n>          * Validate the configuration against the desired path and, if the\n> -        * platform supports it, the dewarper.\n> +        * platform supports it, the dewarper. While iterating over the\n> +        * configurations collect the smallest common sensor format.\n>          */\n> +       Size accumulatedSensorSize;\n>         auto validateConfig = [&](StreamConfiguration &cfg, RkISP1Path *path,\n>                                   Stream *stream, Status expectedStatus) {\n>                 StreamConfiguration tryCfg = cfg;\n>  \n> +               /* Need to validate the path before the transpose */\n> +               if (transposeAfterIsp)\n> +                       tryCfg.size.transpose();\n> +\n>                 Status ret = path->validate(sensor, sensorConfig, &tryCfg);\n>                 if (ret == Invalid)\n>                         return false;\n> @@ -650,6 +666,8 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>                     (expectedStatus == Valid && ret == Adjusted))\n>                         return false;\n>  \n> +               Size sensorSize = tryCfg.size;\n> +\n>                 if (useDewarper) {\n>                         /*\n>                          * The dewarper output is independent of the ISP path.\n> @@ -672,6 +690,8 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>  \n>                 cfg = tryCfg;\n>                 cfg.setStream(stream);\n> +\n> +               accumulatedSensorSize = std::max(accumulatedSensorSize, sensorSize);\n>                 return true;\n>         };\n>  \n> @@ -722,13 +742,6 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>                 return Invalid;\n>         }\n>  \n> -       /* Select the sensor format. */\n> -       Size maxSize;\n> -\n> -       for (const StreamConfiguration &cfg : config_) {\n> -               maxSize = std::max(maxSize, cfg.size);\n> -       }\n> -\n>         std::vector<unsigned int> mbusCodes;\n>  \n>         if (isRaw) {\n> @@ -739,7 +752,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n>                                [](const auto &value) { return value.second; });\n>         }\n>  \n> -       sensorFormat_ = sensor->getFormat(mbusCodes, maxSize,\n> +       sensorFormat_ = sensor->getFormat(mbusCodes, accumulatedSensorSize,\n>                                           mainPath->maxResolution());\n>  \n>         if (sensorFormat_.size.isNull())\n> @@ -774,6 +787,22 @@ PipelineHandlerRkISP1::generateConfiguration(Camera *camera,\n>         if (roles.empty())\n>                 return config;\n>  \n> +       Transform transform = Transform::Identity;\n> +       Size previewSize = kRkISP1PreviewSize;\n> +       bool transposeAfterIsp = false;\n> +       if (data->canUseDewarper_) {\n> +               transform = Orientation::Rotate0 / data->sensor_->mountingOrientation();\n> +               if (!!(transform & Transform::Transpose))\n> +                       transposeAfterIsp = true;\n> +       }\n> +\n> +       /*\n> +        * In case of a transpose transform we need to create a path for the\n> +        * transposed size.\n> +        */\n> +       if (transposeAfterIsp)\n> +               previewSize.transpose();\n> +\n>         /*\n>          * As the ISP can't output different color spaces for the main and self\n>          * path, pick a sensible default color space based on the role of the\n> @@ -802,7 +831,7 @@ PipelineHandlerRkISP1::generateConfiguration(Camera *camera,\n>                         if (!colorSpace)\n>                                 colorSpace = ColorSpace::Sycc;\n>  \n> -                       size = kRkISP1PreviewSize;\n> +                       size = previewSize;\n>                         break;\n>  \n>                 case StreamRole::VideoRecording:\n> @@ -810,7 +839,7 @@ PipelineHandlerRkISP1::generateConfiguration(Camera *camera,\n>                         if (!colorSpace)\n>                                 colorSpace = ColorSpace::Rec709;\n>  \n> -                       size = kRkISP1PreviewSize;\n> +                       size = previewSize;\n>                         break;\n>  \n>                 case StreamRole::Raw:\n> @@ -852,6 +881,9 @@ PipelineHandlerRkISP1::generateConfiguration(Camera *camera,\n>                 if (!cfg.pixelFormat.isValid())\n>                         return nullptr;\n>  \n> +               if (transposeAfterIsp && role != StreamRole::Raw)\n> +                       cfg.size.transpose();\n> +\n>                 cfg.colorSpace = colorSpace;\n>                 cfg.bufferCount = kRkISP1MinBufferCount;\n>                 config->addConfiguration(cfg);\n> @@ -874,6 +906,19 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n>         if (ret)\n>                 return ret;\n>  \n> +       const PixelFormat &streamFormat = config->at(0).pixelFormat;\n> +       const PixelFormatInfo &info = PixelFormatInfo::info(streamFormat);\n> +       isRaw_ = info.colourEncoding == PixelFormatInfo::ColourEncodingRAW;\n> +       data->usesDewarper_ = data->canUseDewarper_ && !isRaw_;\n> +\n> +       Transform transform = config->combinedTransform();\n> +       bool transposeAfterIsp = false;\n> +       if (data->usesDewarper_) {\n> +               if (!!(transform & Transform::Transpose))\n> +                       transposeAfterIsp = true;\n> +               transform = Transform::Identity;\n> +       }\n> +\n>         /*\n>          * Configure the format on the sensor output and propagate it through\n>          * the pipeline.\n> @@ -883,10 +928,10 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n>  \n>         if (config->sensorConfig)\n>                 ret = sensor->applyConfiguration(*config->sensorConfig,\n> -                                                config->combinedTransform(),\n> +                                                transform,\n>                                                  &format);\n>         else\n> -               ret = sensor->setFormat(&format, config->combinedTransform());\n> +               ret = sensor->setFormat(&format, transform);\n>  \n>         if (ret < 0)\n>                 return ret;\n> @@ -913,10 +958,6 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n>                 << \" crop \" << inputCrop;\n>  \n>         Rectangle outputCrop = inputCrop;\n> -       const PixelFormat &streamFormat = config->at(0).pixelFormat;\n> -       const PixelFormatInfo &info = PixelFormatInfo::info(streamFormat);\n> -       isRaw_ = info.colourEncoding == PixelFormatInfo::ColourEncodingRAW;\n> -       data->usesDewarper_ = dewarper_ && !isRaw_;\n>  \n>         /* YUYV8_2X8 is required on the ISP source path pad for YUV output. */\n>         if (!isRaw_)\n> @@ -1008,15 +1049,19 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n>                                         inputCrop, sensorInfo.analogCrop);\n>                                 auto &vertexMap = dewarper_->vertexMap(cfg.stream());\n>                                 vertexMap.setSensorCrop(sensorCrop);\n> +                               vertexMap.setTransform(config->combinedTransform());\n>                                 data->properties_.set(properties::ScalerCropMaximum, sensorCrop);\n>  \n>                                 /*\n>                                  * Apply a default sensor crop that keeps the\n>                                  * aspect ratio.\n>                                  */\n> -                               Size crop = format.size.boundedToAspectRatio(cfg.size);\n> -                               vertexMap.setScalerCrop(crop.centeredTo(\n> -                                       Rectangle(format.size).center()));\n> +                               Size size = cfg.size;\n> +                               if (transposeAfterIsp)\n> +                                       size.transpose();\n> +                               size = sensorCrop.size().boundedToAspectRatio(size);\n> +                               vertexMap.setScalerCrop(\n> +                                       size.centeredTo(sensorCrop.center()));\n>                         }\n>  \n>                         ret = mainPath_.configure(ispCfg, format);\n> -- \n> 2.48.1\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id DF390C3241\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  6 Nov 2025 13:59:41 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2E805609D8;\n\tThu,  6 Nov 2025 14:59:41 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 51F40606E6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  6 Nov 2025 14:59:39 +0100 (CET)","from neptunite.rasen.tech (unknown\n\t[IPv6:2404:7a81:160:2100:8ce5:1b8c:5343:a04e])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 6F928591;\n\tThu,  6 Nov 2025 14:57:43 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Ezshas7s\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1762437464;\n\tbh=gxDZ4pbyQhD4fAtS1X0oj604Twj6G6t5kHjpQHBwG4A=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=Ezshas7sUMziEOrOxa7F/IbxlhnLuLpaA3QsCGAHtWnbMuq1Fta1WqaBDGtAUtulF\n\tvmZlKSjyTabQX4NEqmB//i51CPcrrgfBbdK4R1W1NKsBPl3/Ded3UbOV6kP9IDPF+v\n\tsLWkQbf/UUzF1okgy6OJPvopk0UzHPs1ixpss7jg=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20251023144841.403689-30-stefan.klug@ideasonboard.com>","References":"<20251023144841.403689-1-stefan.klug@ideasonboard.com>\n\t<20251023144841.403689-30-stefan.klug@ideasonboard.com>","Subject":"Re: [PATCH v2 29/35] libcamera: rkisp1: Handle requested orientation\n\tusing dewarper","From":"Paul Elder <paul.elder@ideasonboard.com>","Cc":"Stefan Klug <stefan.klug@ideasonboard.com>","To":"Stefan Klug <stefan.klug@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Thu, 06 Nov 2025 22:59:32 +0900","Message-ID":"<176243757234.2116251.15219359896207623621@neptunite.rasen.tech>","User-Agent":"alot/0.0.0","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]