Show a patch.

GET /api/1.1/patches/25196/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 25196,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/25196/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/25196/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20251125162851.2301793-18-stefan.klug@ideasonboard.com>",
    "date": "2025-11-25T16:28:29",
    "name": "[v3,17/29] libcamera: rkisp1: Use the dw100 converter module instead of the generic v4l2 converter",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "7679a11791c181501fc78c29d35eae1a0b2642ef",
    "submitter": {
        "id": 184,
        "url": "https://patchwork.libcamera.org/api/1.1/people/184/?format=api",
        "name": "Stefan Klug",
        "email": "stefan.klug@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/25196/mbox/",
    "series": [
        {
            "id": 5613,
            "url": "https://patchwork.libcamera.org/api/1.1/series/5613/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5613",
            "date": "2025-11-25T16:28:12",
            "name": "Full dewarper support on imx8mp",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/5613/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/25196/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/25196/checks/",
    "tags": {},
    "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 545B5C333D\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 25 Nov 2025 16:29:47 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E4C3460AB1;\n\tTue, 25 Nov 2025 17:29:46 +0100 (CET)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D891960AA4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 25 Nov 2025 17:29:44 +0100 (CET)",
            "from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:bae1:340c:573c:570b])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id E5C7D6AF;\n\tTue, 25 Nov 2025 17:27:35 +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=\"MJGSHdeM\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1764088056;\n\tbh=Mk3k5f5BpwZwyQZfSvYKSz5AqfgWwA8+1FTcYbeX7D8=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=MJGSHdeMUQz5E+K8kUcoklpRRnlYnMPkTax0tOIuElcJp02Owbkfb+DcNy8zguJKa\n\t9Bb3xBdM0wpZSK/c5wdR+UcomWWEhHgNOWYEY4/DAdSnAXsayw8fN5TrnOfAfGsJbJ\n\tXuxi5XlraKoUxfj8ZT47chS6PWShv+HIoQzmkVKw=",
        "From": "Stefan Klug <stefan.klug@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Stefan Klug <stefan.klug@ideasonboard.com>",
        "Subject": "[PATCH v3 17/29] libcamera: rkisp1: Use the dw100 converter module\n\tinstead of the generic v4l2 converter",
        "Date": "Tue, 25 Nov 2025 17:28:29 +0100",
        "Message-ID": "<20251125162851.2301793-18-stefan.klug@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.51.0",
        "In-Reply-To": "<20251125162851.2301793-1-stefan.klug@ideasonboard.com>",
        "References": "<20251125162851.2301793-1-stefan.klug@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "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>"
    },
    "content": "The dewarper integration into the rkisp1 pipeline is quite complicated.\nSimplify that by switching to the now available ConverterDW100Module. As\nthere is no other known converter in combination with th rkisp1 ISP this\nis a safe step to do.\n\nThis change also paves the way to implement dw100 specific features later.\n\nThe input crop implemented in the dw100 kernel driver is quite limited\nin that it doesn't allow arbitrary crop rectangles but only scale\nfactors quantized to the underlying fixed point representation and only\naspect ratio preserving crops.\n\nThe vertex map based implementation allows for pixel perfect crops. The\nonly downside is that ScalerCrop can no longer be set dynamically on\nolder kernels. A corresponding warning is already implemented in the\nconverter module.\n\nSigned-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n\n---\n\nChanges in v3:\n- Merge usage of the converter module and ScalerCrop handling into one\n  patch as it is difficult to keep them separate with the new module\nconcept\n\nChanges in 0.9:\n- Code cleanup\n- Update vertex map before start() to partially support old kernels\n\nChanges in 0.7:\n- Removed double call to applyVertexMap()\n---\n src/libcamera/pipeline/rkisp1/rkisp1.cpp | 122 ++++++-----------------\n 1 file changed, 33 insertions(+), 89 deletions(-)",
    "diff": "diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\nindex 138e1d5bf06b..6256a67bc31e 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n@@ -36,7 +36,7 @@\n #include \"libcamera/internal/camera.h\"\n #include \"libcamera/internal/camera_sensor.h\"\n #include \"libcamera/internal/camera_sensor_properties.h\"\n-#include \"libcamera/internal/converter/converter_v4l2_m2m.h\"\n+#include \"libcamera/internal/converter/converter_dw100.h\"\n #include \"libcamera/internal/delayed_controls.h\"\n #include \"libcamera/internal/device_enumerator.h\"\n #include \"libcamera/internal/framebuffer.h\"\n@@ -232,10 +232,7 @@ private:\n \tRkISP1MainPath mainPath_;\n \tRkISP1SelfPath selfPath_;\n \n-\tstd::unique_ptr<V4L2M2MConverter> dewarper_;\n-\tRectangle scalerMaxCrop_;\n-\n-\tstd::optional<Rectangle> activeCrop_;\n+\tstd::unique_ptr<ConverterDW100Module> dewarper_;\n \n \t/* Internal buffers used when dewarper is being used */\n \tstd::vector<std::unique_ptr<FrameBuffer>> mainPathBuffers_;\n@@ -940,6 +937,16 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n \tif (ret)\n \t\treturn ret;\n \n+\t/*\n+\t* Apply the actual sensor crop, for proper\n+\t* dewarp map calculation\n+\t*/\n+\tRectangle sensorCrop = outputCrop.transformedBetween(\n+\t\tinputCrop, sensorInfo.analogCrop);\n+\tif (data->usesDewarper_)\n+\t\tdewarper_->setSensorCrop(sensorCrop);\n+\tdata->properties_.set(properties::ScalerCropMaximum, sensorCrop);\n+\n \tstd::map<unsigned int, IPAStream> streamConfig;\n \tstd::vector<std::reference_wrapper<StreamConfiguration>> outputCfgs;\n \n@@ -965,13 +972,15 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n \t\t\t\t\treturn ret;\n \n \t\t\t\t/*\n-\t\t\t\t * Calculate the crop rectangle of the data\n-\t\t\t\t * flowing into the dewarper in sensor\n-\t\t\t\t * coordinates.\n+\t\t\t\t * Apply a default scaler crop that keeps the\n+\t\t\t\t * aspect ratio.\n \t\t\t\t */\n-\t\t\t\tscalerMaxCrop_ =\n-\t\t\t\t\toutputCrop.transformedBetween(inputCrop,\n-\t\t\t\t\t\t\t\t      sensorInfo.analogCrop);\n+\t\t\t\tSize size = cfg.size;\n+\t\t\t\tsize = sensorCrop.size().boundedToAspectRatio(size);\n+\n+\t\t\t\tControlList ctrls;\n+\t\t\t\tctrls.set(controls::ScalerCrop, size.centeredTo(sensorCrop.center()));\n+\t\t\t\tdewarper_->setControls(cfg.stream(), ctrls);\n \t\t\t}\n \n \t\t\tret = mainPath_.configure(ispCfg, format);\n@@ -1165,6 +1174,9 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] const ControlL\n \t\tactions += [&]() { stat_->streamOff(); };\n \n \t\tif (data->usesDewarper_) {\n+\t\t\tif (controls)\n+\t\t\t\tdewarper_->setControls(&data->mainPathStream_, *controls);\n+\n \t\t\tret = dewarper_->start();\n \t\t\tif (ret) {\n \t\t\t\tLOG(RkISP1, Error) << \"Failed to start dewarper\";\n@@ -1315,28 +1327,8 @@ int PipelineHandlerRkISP1::updateControls(RkISP1CameraData *data)\n {\n \tControlInfoMap::Map controls;\n \n-\tif (data->usesDewarper_) {\n-\t\tstd::pair<Rectangle, Rectangle> cropLimits;\n-\t\tif (dewarper_->isConfigured(&data->mainPathStream_))\n-\t\t\tcropLimits = dewarper_->inputCropBounds(&data->mainPathStream_);\n-\t\telse\n-\t\t\tcropLimits = dewarper_->inputCropBounds();\n-\n-\t\t/*\n-\t\t * ScalerCrop is specified to be in Sensor coordinates.\n-\t\t * So we need to transform the limits to sensor coordinates.\n-\t\t * We can safely assume that the maximum crop limit contains the\n-\t\t * full fov of the dewarper.\n-\t\t */\n-\t\tRectangle min = cropLimits.first.transformedBetween(cropLimits.second,\n-\t\t\t\t\t\t\t\t    scalerMaxCrop_);\n-\n-\t\tcontrols[&controls::ScalerCrop] = ControlInfo(min,\n-\t\t\t\t\t\t\t      scalerMaxCrop_,\n-\t\t\t\t\t\t\t      scalerMaxCrop_);\n-\t\tdata->properties_.set(properties::ScalerCropMaximum, scalerMaxCrop_);\n-\t\tactiveCrop_ = scalerMaxCrop_;\n-\t}\n+\tif (data->usesDewarper_)\n+\t\tdewarper_->updateControlInfos(&data->mainPathStream_, controls);\n \n \t/* Add the IPA registered controls to list of camera controls. */\n \tfor (const auto &ipaControl : data->ipaControls_)\n@@ -1376,8 +1368,6 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)\n \t/* Initialize the camera properties. */\n \tdata->properties_ = data->sensor_->properties();\n \n-\tscalerMaxCrop_ = Rectangle(data->sensor_->resolution());\n-\n \tconst CameraSensorProperties::SensorDelays &delays = data->sensor_->sensorDelays();\n \tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n \t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n@@ -1472,27 +1462,11 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator)\n \tstat_->bufferReady.connect(this, &PipelineHandlerRkISP1::statBufferReady);\n \tparam_->bufferReady.connect(this, &PipelineHandlerRkISP1::paramBufferReady);\n \n-\t/* If dewarper is present, create its instance. */\n-\tDeviceMatch dwp(\"dw100\");\n-\tdwp.add(\"dw100-source\");\n-\tdwp.add(\"dw100-sink\");\n-\n-\tstd::shared_ptr<MediaDevice> dwpMediaDevice = enumerator->search(dwp);\n-\tif (dwpMediaDevice) {\n-\t\tdewarper_ = std::make_unique<V4L2M2MConverter>(dwpMediaDevice);\n-\t\tif (dewarper_->isValid()) {\n-\t\t\tdewarper_->outputBufferReady.connect(\n-\t\t\t\tthis, &PipelineHandlerRkISP1::dewarpBufferReady);\n-\n-\t\t\tLOG(RkISP1, Info)\n-\t\t\t\t<< \"Found DW100 dewarper \" << dewarper_->deviceNode();\n-\t\t} else {\n-\t\t\tLOG(RkISP1, Warning)\n-\t\t\t\t<< \"Found DW100 dewarper \" << dewarper_->deviceNode()\n-\t\t\t\t<< \" but invalid\";\n-\n-\t\t\tdewarper_.reset();\n-\t\t}\n+\tdewarper_ = ConverterDW100Module::createModule(enumerator);\n+\tif (dewarper_) {\n+\t\tdewarper_->outputBufferReady.connect(\n+\t\t\tthis, &PipelineHandlerRkISP1::dewarpBufferReady);\n+\t\tLOG(RkISP1, Debug) << \"Found DW100 dewarper\";\n \t}\n \n \t/*\n@@ -1603,37 +1577,7 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer)\n \t\treturn;\n \t}\n \n-\t/* Handle scaler crop control. */\n-\tconst auto &crop = request->controls().get(controls::ScalerCrop);\n-\tif (crop) {\n-\t\tRectangle rect = crop.value();\n-\n-\t\t/*\n-\t\t * ScalerCrop is specified to be in Sensor coordinates.\n-\t\t * So we need to transform it into dewarper coordinates.\n-\t\t * We can safely assume that the maximum crop limit contains the\n-\t\t * full fov of the dewarper.\n-\t\t */\n-\t\tstd::pair<Rectangle, Rectangle> cropLimits =\n-\t\t\tdewarper_->inputCropBounds(&data->mainPathStream_);\n-\n-\t\trect = rect.transformedBetween(scalerMaxCrop_, cropLimits.second);\n-\t\tint ret = dewarper_->setInputCrop(&data->mainPathStream_,\n-\t\t\t\t\t\t  &rect);\n-\t\trect = rect.transformedBetween(cropLimits.second, scalerMaxCrop_);\n-\t\tif (!ret && rect != crop.value()) {\n-\t\t\t/*\n-\t\t\t * If the rectangle is changed by setInputCrop on the\n-\t\t\t * dewarper, log a debug message and cache the actual\n-\t\t\t * applied rectangle for metadata reporting.\n-\t\t\t */\n-\t\t\tLOG(RkISP1, Debug)\n-\t\t\t\t<< \"Applied rectangle \" << rect.toString()\n-\t\t\t\t<< \" differs from requested \" << crop.value().toString();\n-\t\t}\n-\n-\t\tactiveCrop_ = rect;\n-\t}\n+\tdewarper_->setControls(&data->mainPathStream_, request->controls());\n \n \t/*\n \t * Queue input and output buffers to the dewarper. The output\n@@ -1642,7 +1586,7 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer)\n \t */\n \tint ret = dewarper_->queueBuffers(buffer, request->buffers());\n \tif (ret < 0) {\n-\t\tLOG(RkISP1, Error) << \"Cannot queue buffers to dewarper: \"\n+\t\tLOG(RkISP1, Error) << \"Failed to queue buffers to dewarper: -\"\n \t\t\t\t   << strerror(-ret);\n \n \t\tcancelDewarpRequest(info);\n@@ -1650,7 +1594,7 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer)\n \t\treturn;\n \t}\n \n-\trequest->metadata().set(controls::ScalerCrop, activeCrop_.value());\n+\tdewarper_->populateMetadata(&data->mainPathStream_, request->metadata());\n }\n \n void PipelineHandlerRkISP1::dewarpBufferReady(FrameBuffer *buffer)\n",
    "prefixes": [
        "v3",
        "17/29"
    ]
}