From patchwork Thu Oct 29 13:26:29 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ray Strode X-Patchwork-Id: 28699 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 C84A6C3261 for ; Thu, 29 Oct 2026 13:27:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 80FD0690CE; Thu, 29 Oct 2026 14:27:24 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="dkzkXH6N"; dkim-atps=neutral Received: from mail-vs1-xe36.google.com (mail-vs1-xe36.google.com [IPv6:2607:f8b0:4864:20::e36]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E80E4690AD for ; Thu, 29 Oct 2026 14:27:22 +0100 (CET) Received: by mail-vs1-xe36.google.com with SMTP id ada2fe7eead31-7cc365db987so1240070137.0 for ; Thu, 29 Oct 2026 06:27:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793280442; x=1793885242; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=k02R0dOKvGKKUWEKpipLqZBuCumZlT8j3xKek7NANnw=; b=dkzkXH6N7R+sDUnftxyHelIvhv0IvYhPLyzFF3v2zMEiVDZcFeU0RPX4Pg9DqKQy8J XqphhhtIgUg8fVZENz/pvqfwxcOKUCcHst7lTsrVIExZZKs0Vn9DPEKUJcaafiDHPv7v HqXDWy6I8H+pyFrcSIxZ/N6dqYJm0aZBKJxQ5nPCua87FxpXsBC3Bpx1fKPfmOmyh66l O/e758qFnvokQ9aFHjT56ngv2cqSaGsq+minN5eWQ9gcVvWIF5K6kZnjgB86p8wQmFpJ gvdenaiWryJey+LbuaGBtfUsqULgE6SiHswx1R0udrsr1rBWra4e/ZqvoLV0nNV3dSWr snGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793280442; x=1793885242; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=k02R0dOKvGKKUWEKpipLqZBuCumZlT8j3xKek7NANnw=; b=Wgw6+Tx3EufLjkuUsnSlZuGL4Y/wD35NghSKaSOykwD+spnSf7SjzmJVuA3cGb9wa5 vvs//CsgAznycTGknE7hPSW2Q5waCXQlNxFt4dK2EqwdHOIWkPkzfngtjTTieVM1adHx UEdUCuNCUt/ltTfuTCgOkLGUrW+dMMI3Zdq0rhTvl0sU/rjXuA5IxFeevYhZjXJgrmNA 5JgzJQ8ICJk2/CzBkrdN+lz2kHJxUgCVcUPBjdZPB64xXWDO9Qxf9TtHUIP9IG12QMlK VT0+YNSs/UN8mv+XsMZJnf1qaJZJHKj/XmpOuXfO3z/lIQXoVWw2RUpTKmpR5K9GDfNP kU6g== X-Gm-Message-State: AFq9FYJFzq1QiSSE2j/B2wE7vXgEZTjMJrFLM/NQjYNJ2ElIFjP63lVR T09NXCdmmaH9C46PhpYT0+mKpHu5i0/5f8vH97slEU3ySq5rvWlI0+HqonaKcOaGBlo= X-Gm-Gg: AYBFou1dVaqw/yYmXG45PLw2cDmIq5epTz6jUQ8scsn/0xx68lZSlv12aDXLvpkOP7A SHakzl6G/zKjtz0kUCdQH7VHJPXgqw3089shinVDHqfeICG8VmAl6OUhrh3mIjiW94wVSq2+SOI jABw5d+NOLIhmfixiHAhOe6pfKeIdbTLZ9n3D+MDslX8M6vZ6rJcyt4OT6NtqQwjWLqd2+HoZ9E 4CVkuRqbSR+O4ue2gBQijmJRsDmh1s/RFZx4uUy7pDnwwdGzZ0nWjonsWcoomIstMm6m85ca+jL CkIx8diYz1iVHWp7FJGTs+T19twcD6PWB4sNqPNd7V3D+eqv+ltfFQTpEFsjdbX21o7eh9SvlOl 9bAZSok+VhNPQwsIBw51nNFO9Gr8e6tFJ2UpsD8/9u50OXji6Wje44rYRE849aZD/j8mk8H0Lq7 CwQfd5zFy+sqU1iRF1u052cPiYP4AwxBaV0AxnZBElW7ziXkoORD1GV4hKW25jQA+Rn3FU5FLk8 +5nnXGofIQTOh49znZ0dayW5Em/JJMrn1YJDQReFI0sGEsrZiz+YVeyOMv6vM7iUN5ZPn+qE15C f9q9MeFpxmxgtu+uROG6L7aNjFXh3vEiycOMTLT/aGr1WFmXk5hwdV/akBPK9oQU9rjiiuJd9I7 rmPs= X-Received: by 2002:a05:6102:418d:b0:7cc:3eb0:6ef5 with SMTP id ada2fe7eead31-7d03a4baae8mr2817813137.11.1793280441684; Thu, 29 Oct 2026 06:27:21 -0700 (PDT) Received: from localhost ([144.121.52.163]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-99125931983sm9476046241.2.2026.10.29.06.27.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Oct 2026 06:27:20 -0700 (PDT) From: Ray Strode To: libcamera-devel@lists.libcamera.org Cc: kieran.bingham@ideasonboard.com, bod.linux@nxsw.ie, laurent.pinchart@ideasonboard.com, stefan.klug@ideasonboard.com, martincarvalho@gmail.com Subject: [PATCH v4 7/9] tests: Validate native sensor crop coordinates Date: Thu, 29 Oct 2026 09:26:29 -0400 Message-ID: <20261029132631.370507-8-halfline@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261029132631.370507-1-halfline@gmail.com> References: <20261016202818.1405645-1-halfline@gmail.com> <20261029132631.370507-1-halfline@gmail.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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Ray Strode This commit checks the conversion from debayer crop rectangles to native sensor coordinates in the existing geometry unit test. The new cases cover GPU and CPU crop sizes, physical pixel array origins, binning, flips, transposition and fractional coordinates. An odd image boundary checks that the conversion preserves image geometry before Bayer statistics alignment. Signed-off-by: Ray Strode --- test/debayer-geometry.cpp | 45 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/test/debayer-geometry.cpp b/test/debayer-geometry.cpp index cfc757fa..f2f0bc09 100644 --- a/test/debayer-geometry.cpp +++ b/test/debayer-geometry.cpp @@ -1,63 +1,106 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2026, Red Hat Inc. * * Sensor crop tests */ #include #include #include "libcamera/internal/software_isp/debayer_geometry.h" #include "test.h" using namespace libcamera; class DebayerGeometryTest : public Test { protected: int run() override { - if (testCrop()) + if (testCrop() || testSensorCrop()) return TestFail; return TestPass; } private: int testCrop() { static const struct { Size input; Size native; Size output; Rectangle expected; } cases[] = { { { 1920, 1080 }, { 1920, 1080 }, { 1920, 1080 }, { 0, 0, 1920, 1080 } }, { { 1928, 1092 }, { 1920, 1092 }, { 1920, 1092 }, { 4, 0, 1920, 1092 } }, /* Output resolution changes must not shrink the sensor window. */ { { 1928, 1092 }, { 1920, 1092 }, { 1920, 1080 }, { 4, 6, 1920, 1080 } }, { { 1928, 1092 }, { 1920, 1092 }, { 1280, 720 }, { 4, 6, 1920, 1080 } }, { { 1928, 1092 }, { 1920, 1092 }, { 640, 480 }, { 236, 0, 1456, 1092 } }, { { 1928, 1092 }, { 1920, 1092 }, { 512, 768 }, { 600, 0, 728, 1092 } }, { { 1928, 1092 }, { 1920, 1092 }, { 1280, 640 }, { 4, 66, 1920, 960 } }, /* A smaller Bayer border leaves an odd top coordinate. */ { { 1928, 1092 }, { 1924, 1092 }, { 1280, 720 }, { 2, 5, 1924, 1082 } }, }; for (const auto &entry : cases) { Rectangle crop = debayerCrop(entry.input, entry.native, entry.output); if (crop != entry.expected) { std::cerr << "Crop " << entry.input << " -> " << entry.output << " is " << crop << ", expected " << entry.expected << std::endl; return TestFail; } } return TestPass; } + + int testSensorCrop() + { + static const struct { + Rectangle crop; + Size input; + Rectangle analog; + Transform transform; + Rectangle expected; + } cases[] = { + /* GPU scaling keeps the full visible sensor region. */ + { { 4, 6, 1920, 1080 }, { 1928, 1092 }, { 0, 0, 1928, 1092 }, Transform::Identity, { 4, 6, 1920, 1080 } }, + /* A full readout keeps its physical pixel-array origin. */ + { { 0, 0, 2000, 1500 }, { 2000, 1500 }, { 8, 8, 4000, 3000 }, Transform::Identity, { 8, 8, 4000, 3000 } }, + /* Sensor crop offsets and 2x binning use native pixels. */ + { { 4, 6, 1920, 1080 }, { 1928, 1092 }, { 100, 200, 3856, 2184 }, Transform::Identity, { 108, 212, 3840, 2160 } }, + /* CPU debayering crops to output size without scaling. */ + { { 324, 186, 1280, 720 }, { 1928, 1092 }, { 100, 200, 3856, 2184 }, Transform::Identity, { 748, 572, 2560, 1440 } }, + /* Preserve an odd image boundary before statistics alignment. */ + { { 2, 5, 1924, 1082 }, { 1928, 1092 }, { 0, 0, 3856, 2184 }, Transform::Identity, { 4, 10, 3848, 2164 } }, + /* Undo sensor flips before reporting the native rectangle. */ + { { 2, 4, 20, 10 }, { 100, 60 }, { 10, 20, 200, 120 }, Transform::HFlip, { 166, 28, 40, 20 } }, + { { 2, 4, 20, 10 }, { 100, 60 }, { 10, 20, 200, 120 }, Transform::VFlip, { 14, 112, 40, 20 } }, + { { 2, 4, 20, 10 }, { 100, 60 }, { 10, 20, 200, 120 }, Transform::HVFlip, { 166, 112, 40, 20 } }, + /* Transposition is undone before the flip. */ + { { 4, 2, 10, 20 }, { 60, 100 }, { 10, 20, 200, 120 }, Transform::Rot270, { 166, 28, 40, 20 } }, + /* Fractional native coordinates and sizes truncate independently. */ + { { 1, 1, 3, 3 }, { 8, 8 }, { 10, 20, 12, 12 }, Transform::Identity, { 11, 21, 4, 4 } }, + }; + + for (const auto &entry : cases) { + Rectangle crop = debayerCropToSensor(entry.crop, entry.input, + entry.analog, + entry.transform); + if (crop != entry.expected) { + std::cerr << "Sensor mapping of " << entry.crop << " in " << entry.input + << " is " << crop << ", expected " << entry.expected << std::endl; + return TestFail; + } + } + + return TestPass; + } }; TEST_REGISTER(DebayerGeometryTest)