From patchwork Thu Oct 29 13:26:25 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ray Strode X-Patchwork-Id: 28695 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 C53F0C3261 for ; Thu, 29 Oct 2026 13:27:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6EB88690BC; Thu, 29 Oct 2026 14:27:07 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="jOI0RTsc"; dkim-atps=neutral Received: from mail-ua1-x934.google.com (mail-ua1-x934.google.com [IPv6:2607:f8b0:4864:20::934]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2A2D2690BB for ; Thu, 29 Oct 2026 14:27:05 +0100 (CET) Received: by mail-ua1-x934.google.com with SMTP id a1e0cc1a2514c-9908e3cd939so629226241.3 for ; Thu, 29 Oct 2026 06:27:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793280424; x=1793885224; 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=qSr2bYahiOdbnIb4c5UFDJoaWJRzP1IKK/iHNfBbWok=; b=jOI0RTscYhABRviVqfrRS1CoBx9IC2O7esYrSbH/xTk76cPzYBLXSRbPhjcMqDNMef sbHnQ7nvZOAPmTyCMBf0DkJDvkDv/BhuwiO6nD1wzAH36OWAYt53HbdGz4KVdVVdHZ7t vNtQb4iZYMfEP45LKxnsSCwsF+yi3r7mpAl8RtetAAKgTMHvhMVNOBDOI298Pkj5axZl 8uiSRh2txwva2RdSKGa3L+nkMep2Vr7+PcAAR5rHfK0vsEgG4gwxNMOXjkNL/LcK55lA GLXf1Ldj72WjYMcr/ucFWhSdlf2MuwS3wm65Y6qlIajnz3XoTAejNCPUcsQkQJpID+CC qlqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793280424; x=1793885224; 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=qSr2bYahiOdbnIb4c5UFDJoaWJRzP1IKK/iHNfBbWok=; b=b+i9yVGqw6ed046ItYFExQIYoMW6SQeJvkGm6FU07qpATO+awB2ei/bnbeM28pY/zz x9048agIB17Vgx+uvi+xfWC3LxgXIFh1N/etX7go4GBu7A4N2n9W1f94MWfjjdI5p2U9 9jJnnoiTQ7Z6xiw+8fTGHBXZJlJxNJzmn/m2oHwjjtSZUQPBSvhDiih3uLCxMJb3805w bdb7qC0ULNQhWlz3OBhEZDLt1BYWf1I7RjrU8YCOCkNz1UxoTKcb6MrSZRHj1l/VryCn 4mmcR9vmCnYxAs7pFi79ncTaaldvIZFq1fRgKkNL4DBRi8Yaeyny9PZTisrzrXRcPzy4 bQdw== X-Gm-Message-State: AFq9FYJ0F9geQeqUsyWqR03i8k1ymDptTxfGrwpRY8XiKqrDhlPtei9m DH/cvY/CcUV+oabN0a1kjf+i/23YwMqToc+GAfiMvFS5BDzGT4OZu6cUgfGyfGpbPYU= X-Gm-Gg: AYBFou2qLv/ZN/78FwKaNFEcLuJysOqQpMk1A4f/TyJdw2pc4ueXZXbaeX52W6BkzWx qDBbH2hE1I1Lu2MH2DsSha+nIzu1PTTWKJE+toLIV3rrQeJSFwljgY24d5Oaxzte6yk66GQ+4vR /RoSk5nZzZ1pxjWX9/nlxTyxhBnhrwM25+6noEllFEmLDIM+/EbYGxRU75k4tb7vq+s4rGwWD4F YOlC8k1Ss5YaVYXRfole1ZnEhQNssdhu5tJ8zwLF2T8yOthMc/i7NBe0O3Dh6olFZStcwYKaMs8 y3JLPGFEyoApcIgYO+b+UFePM9mwELAG9koeUKdpr8X/PCcxoxElH6aVwmGu5mIqlfo93cTFBpc TlJzDNahUYR5nXDTV5bLQEXp1zypT0JF+NgqWKlWYYqWa+JLd6Q1eFM17yNqvXIiYDxWhdwYnSs 7zcmV1+jwITbywfryZY3Rg72u6A3o2wsMkZD/ohO8wDtE89iiRt9Q+zF3NoXODTmgSUXeSGNJ1d 7CmsNRjwsnIa4FqRZ1a7KyJZluvFHqYuU11v1GSUGHKq+NTrvdH/R97CK1n6/cHjNXloX9hionl 9D5QhKtUkzhGWok2lvHIO/Wx3Ngk4pe29nOMBZHRMx09DGB1F3Qqeusv X-Received: by 2002:a05:6102:3309:b0:7c3:a6f0:99cb with SMTP id ada2fe7eead31-7d03a5fece5mr2310985137.33.1793280423699; Thu, 29 Oct 2026 06:27:03 -0700 (PDT) Received: from localhost ([144.121.52.163]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-99125931983sm9476046241.2.2026.10.29.06.27.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Oct 2026 06:27:02 -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 3/9] tests: Validate the visible sensor crop Date: Thu, 29 Oct 2026 09:26:25 -0400 Message-ID: <20261029132631.370507-4-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 adds a geometry unit test with expected sensor rectangles for native, downscaled, wider, narrower, and portrait outputs. It also checks integer rounding that leaves an odd top coordinate before Bayer alignment. Signed-off-by: Ray Strode --- test/debayer-geometry.cpp | 63 +++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 64 insertions(+) create mode 100644 test/debayer-geometry.cpp diff --git a/test/debayer-geometry.cpp b/test/debayer-geometry.cpp new file mode 100644 index 00000000..cfc757fa --- /dev/null +++ b/test/debayer-geometry.cpp @@ -0,0 +1,63 @@ +/* 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()) + 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; + } +}; + +TEST_REGISTER(DebayerGeometryTest) diff --git a/test/meson.build b/test/meson.build index 363a2829..5027b7b1 100644 --- a/test/meson.build +++ b/test/meson.build @@ -25,60 +25,61 @@ endif subdir('libtest') subdir('camera') subdir('controls') subdir('gstreamer') subdir('ipa') subdir('ipc') subdir('log') subdir('media_device') subdir('process') subdir('py') subdir('serialization') subdir('stream') subdir('v4l2_compat') subdir('v4l2_subdevice') subdir('v4l2_videodevice') public_tests = [ {'name': 'color-space', 'sources': ['color-space.cpp']}, {'name': 'geometry', 'sources': ['geometry.cpp']}, {'name': 'public-api', 'sources': ['public-api.cpp']}, {'name': 'signal', 'sources': ['signal.cpp']}, {'name': 'transform', 'sources': ['transform.cpp']}, ] internal_tests = [ {'name': 'bayer-format', 'sources': ['bayer-format.cpp']}, {'name': 'byte-stream-buffer', 'sources': ['byte-stream-buffer.cpp']}, {'name': 'camera-sensor', 'sources': ['camera-sensor.cpp']}, + {'name': 'debayer-geometry', 'sources': ['debayer-geometry.cpp']}, {'name': 'delayed_controls', 'sources': ['delayed_controls.cpp']}, {'name': 'event', 'sources': ['event.cpp']}, {'name': 'event-dispatcher', 'sources': ['event-dispatcher.cpp']}, {'name': 'event-thread', 'sources': ['event-thread.cpp']}, {'name': 'file', 'sources': ['file.cpp']}, {'name': 'flags', 'sources': ['flags.cpp']}, {'name': 'hotplug-cameras', 'sources': ['hotplug-cameras.cpp']}, {'name': 'matrix', 'sources': ['matrix.cpp']}, {'name': 'message', 'sources': ['message.cpp']}, {'name': 'object', 'sources': ['object.cpp']}, {'name': 'object-delete', 'sources': ['object-delete.cpp']}, {'name': 'object-invoke', 'sources': ['object-invoke.cpp']}, {'name': 'pixel-format', 'sources': ['pixel-format.cpp']}, {'name': 'shared-fd', 'sources': ['shared-fd.cpp']}, {'name': 'signal-threads', 'sources': ['signal-threads.cpp']}, {'name': 'threads', 'sources': 'threads.cpp', 'dependencies': [libthreads]}, {'name': 'timer', 'sources': ['timer.cpp']}, {'name': 'timer-fail', 'sources': ['timer-fail.cpp'], 'should_fail': true}, {'name': 'timer-thread', 'sources': ['timer-thread.cpp']}, {'name': 'unique-fd', 'sources': ['unique-fd.cpp']}, {'name': 'utils', 'sources': ['utils.cpp']}, {'name': 'value-node', 'sources': ['value-node.cpp']}, {'name': 'vector', 'sources': ['vector.cpp']}, {'name': 'yaml-parser', 'sources': ['yaml-parser.cpp']}, ] internal_non_parallel_tests = [ {'name': 'fence', 'sources': ['fence.cpp']}, {'name': 'mapped-buffer', 'sources': ['mapped-buffer.cpp']}, ]