From patchwork Thu Oct 29 15:20:52 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ray Strode X-Patchwork-Id: 28708 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 DCF4BC324C for ; Thu, 29 Oct 2026 15:21:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8B4C6690B0; Thu, 29 Oct 2026 16:21:52 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="g+876WpO"; dkim-atps=neutral Received: from mail-vs1-xe29.google.com (mail-vs1-xe29.google.com [IPv6:2607:f8b0:4864:20::e29]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9373A690A0 for ; Thu, 29 Oct 2026 16:21:50 +0100 (CET) Received: by mail-vs1-xe29.google.com with SMTP id ada2fe7eead31-7cc1cf48a39so852340137.1 for ; Thu, 29 Oct 2026 08:21:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793287309; x=1793892109; 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=g+876WpOXouVxArXeRHARUvwbKZHUb16iM4uX4dlpzyDVJPNeSItCSDXCeI9rjkgSU eGP1etqmJ5JVVMU/+47iTvhmlLlTq/e+St7WeVmC2MLjEcz+nMBE4CtXZG9VSV0fyIG/ yUizyrgSlGIvY8LrSN7PEDsu0CvS5NXrVXyDKBTEwPtqWJzMi2/xHsMWP1KVBkBo40no EHe5PryoUpvkjo9CXFFYcI6s7GI7a83eMezHI+WddzAoMCFZlXDZHySK6lwV+uAxlzGU 2VziyghHSr3wvMjDcSBAt1HaQpiei0P36irvVuO8KGdVLiB9VsyzHfCHOehyK+D01cUE +yTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793287309; x=1793892109; 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=2WkUCY16t8RXGMHJmZd0jpjOtgt2nNHYCL5Vof8laWOa9PcHo5BkCGmR89AqPuaz+e 5GKAIB5uIpPyiUOIEe5brHPE8ZllrKVb6jcsDUJXdUIZzAV4CIkTSCR8JK9W1Tc1+OEG XkSayboHJW/Jmrjv1TZumvyxdnjpLIQbuo2FUrsn8K+hmTTTrxpTaw0M/v3s5fgpgZ5u WgsIXuuNxgYyCsUsEqgAUwPYcoNsOw6I3T6Fvuixv2KP4kDvDpzGiBlOKA7faF725cqY Zr2rnCRlP5yDBumOTAobY6iFzYIqR7xefH50sl84Hy8zY32de4yslVfoekaetrp16VwZ 1ssw== X-Gm-Message-State: AFq9FYLWTjRMlIpI9MST0UY9mqL5YFQP1xA2vWZZ86dj8kpA3fyhJhEm BimNVWmSFYXg6G2MsL37LG9HPSuA3SbvT+heYrVHrU4sAxrmQDxV2AiFTwMBXqBBh1s= X-Gm-Gg: AYBFou1ro2RdswPFqX6L6ID/Z2Cup6HILJRZ/jxqJ2TCcz1u1apGTswtl/tERwkaHmg 9wXh0NYrU2YOq+jYn+JJzEX7SODCtHt2+yWgTSVf+mUulR1HZb2AkygZhHz/dTZDN7om7l/v8EV iIkBg4ta/r24qvbcUwP56ng6lW5tIh6TpjwLR1J1abSdIjcRuVQUkLHP8WG+0cFhURC8TDIihAl pVqo1UE68h84oBiFVtdmrg8lUgAFixpQb6oEwoIuo+taumiyTu4tdVmQ+2o5pkSgf7rklBI9wzM 7Gn4OprAygwBkD+6mIHG3NLmHLDIzeBCFUP0ApieVaJQwkOJCPM1IJSOpaiJxIxKUbiliWHT2Tx r50jw9gDsM5Nx/qyDHzom5kxES0ot+2u/d/gnk0LGo3E+IUEEXg0z901+WYmOMOD1ZLScJhT2aG ZJXPkrEHnO4LtMLuR6JZSA71HbzTI6CYH17OtZ98LufSQI2AcGf5/ZLe9CuITiGbjqlJbMOSS2w l4DT6GuOTgh39ZrZKs9B7LdhdsVES2AqO5aMqE6eqUTIDyeQrzAb0WYtebOIP9eSZYV2/xwUyXZ kaSCDo0Odxi0VzKB2udoFLaKTk9PeQn20cGPxnAZkElinFptel/F25lU6ddYSRxHcXzeOIahq+e o7g== X-Received: by 2002:a05:6102:2b9c:b0:7b5:4700:3a6a with SMTP id ada2fe7eead31-7d03a5bd56emr2570905137.26.1793287309311; Thu, 29 Oct 2026 08:21:49 -0700 (PDT) Received: from localhost ([144.121.52.163]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-991f74e5e22sm206563241.4.2026.10.29.08.21.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Oct 2026 08:21:47 -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 05/11] tests: Validate the visible sensor crop Date: Thu, 29 Oct 2026 11:20:52 -0400 Message-ID: <20261029152058.896209-6-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 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']}, ]