From patchwork Thu Oct 29 15:20:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ray Strode X-Patchwork-Id: 28712 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 7E9B4C3261 for ; Thu, 29 Oct 2026 15:22:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 28287690DE; Thu, 29 Oct 2026 16:22:07 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="r8ZmC/37"; dkim-atps=neutral Received: from mail-ua1-x930.google.com (mail-ua1-x930.google.com [IPv6:2607:f8b0:4864:20::930]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6F337690A0 for ; Thu, 29 Oct 2026 16:22:05 +0100 (CET) Received: by mail-ua1-x930.google.com with SMTP id a1e0cc1a2514c-9908c849564so666724241.3 for ; Thu, 29 Oct 2026 08:22:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793287324; x=1793892124; 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=r8ZmC/37FHbv2iJlD3xfrfTLOzTx5mkrOoqKdvKXOv5HDuxX13oW1VhqZmjsRgdEBD Q/xWR8fhBslKahqSCcWcfApwJCp0vV4eChLkgD7TW8Nf8IJ6BL/WV4WI8vp21GTSBDLv E6x4sqIEkP2WlYBgV94Gwb8cmbaUph2nzsYve4lExtVEeY/H9d8iMgIZWmAiHPKs/iTG fL+J712TmWdB6AXDXEdOK3tNjpj9CgWuFn0YCB4W2kt8do5twWOZWknNQgGXijwmz5XW RFXLfioiPf9Tlzc0h97EA/xOcZLtpJtvUGRazyAufSJEnN22QNUKZdLgbKP/3rfboIoi AjLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793287324; x=1793892124; 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=VXFKSlyYQOgCIHSeBQCx5bYFBzatQC7EiJ0fWGi817zT/Y+slkVel+2j9mTdhbNwTf 70NOaU6DI1nKJEsJh5xkTTpLsjWwq5MIGUuu3u9hmMTOBImW8zUTwj9uuqrtPNsQ4GKN 9vMhNhySM0YJ+8It2XAKDD5R5q2l6Zm8/u8v/RDZEUt3r6PZJl6vdhJeN3bjq381vXtN iv3Ev8W9X2+1YSaMszTiAGcPlw4UKHAuHUNI8j9DE9vSDYfcZiHEJDV2qRJJn9SS1T8V PqGDrqDNxdima/L6QUxFE7qYuhR4PtFQbvXOEoB3CYkJyA+F3MpcBVXADCp8VtIUEAzZ vNbQ== X-Gm-Message-State: AFq9FYKwoLexqSARBqVFJvDjR6/sXfcBLL+hNpDya9qQdwRjkjHC+7Tt eTNgFkWRY9q9mbaCITe5Qb++EVR+xgmUIKwIaKlkr6tVYuoEjTOpsF87cO8P7Vv/eNg= X-Gm-Gg: AYBFou1n/M2rf7ARd69QgAFOyjr6l2fqmA9fxd/CUUo7uCtWD1hmlXY9NYJRuFNYZyS GNko11+OfXGiRAhNV/AWRIlhpKJf32P+tVUh9CFSs8YcRmk3TtY+ZYapxd+kfjHMVEm5iQN1WDc xRfYUzef7tgev59tBUNqjv8K2p6BSZdtqkCcmYqM3LfUndb+c6/TBkFipcKlt1QAp7Z3DMpwlcG KVXJG/buqi9c9fjgKZ9rwOkI0qh91Halp5hMCTDG95wf24X4M4lS0knoSaPTtCXrav2QXBqUVOQ gP4i9s0b2ior8ksU5texN12oh7gEMsAd76tlXy5Pl+b8S5T2yOfKbdoStnf8SHnyrsPtQV7VxIO 6SWrRf3yfivEmgvVG7krYHMUkQG/wDzx4Y3MjKAmBRXemXCBjDhYXnSOZnSRPDVbboduKgUuO4n GQvfluaH+n/Ogq0NSiw4RbOtLS5tKKTcc24gUQ4+pdPKWOD7maPQFv2nGy5VwlR5r+RXiuZIJMC /PySxLTPdUx/djYuGMAppP0Armf7D+CGpMpgO9fbSvmFkJr6hQYFi6ACFehWilfr1hjK/46LE3y FYFSx9grbeMED6qQAfdec8jBHuUJQrZ35E0xVSzBVK4enKmy1zBlSrgV X-Received: by 2002:a05:6102:2b9c:b0:7cc:1192:563c with SMTP id ada2fe7eead31-7d03a5d6b85mr2513305137.25.1793287324207; Thu, 29 Oct 2026 08:22:04 -0700 (PDT) Received: from localhost ([144.121.52.163]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-991f74e5e22sm206563241.4.2026.10.29.08.22.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Oct 2026 08:22:03 -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 v5 09/11] tests: Validate native sensor crop coordinates Date: Thu, 29 Oct 2026 11:20:56 -0400 Message-ID: <20261029152058.896209-10-halfline@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261029152058.896209-1-halfline@gmail.com> References: <20261029152058.896209-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)