From patchwork Thu Oct 15 22:36:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ray Strode X-Patchwork-Id: 28468 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 AC934C3305 for ; Thu, 15 Oct 2026 22:36:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6E24568E1A; Fri, 16 Oct 2026 00:36:18 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="r0l7CXsQ"; 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 0633968E0E for ; Fri, 16 Oct 2026 00:36:16 +0200 (CEST) Received: by mail-vs1-xe36.google.com with SMTP id ada2fe7eead31-7bec5112765so1220370137.1 for ; Thu, 15 Oct 2026 15:36:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792103775; x=1792708575; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=tpQG5TITpEcD3UodzKOR9pLgXTFAPmutRocyMUkOoMo=; b=r0l7CXsQp8bND44ISCh3TRFIsYYVtLR+dKwCzJjBJLB2+LeRgQKM+aP53PPRFpkPhR Mr/TIuINJ7ZNXOtRaTGAuc6SGdKjwuYyVvr0NpStZctmWdHRFGvFTFO9pDVUQ7fBf/td 5anWg3jeHNaCBB3BMFt8AmH2fEBkoaH6nWqYNQZmqKzHkXVl6953VTsFDD8CyyvgCnVF IGa1MxwX+ToauSXB48vA6LDah8br9MtLWbahPrIGxhjk134JAZJoAo/Z5qNxNiBzYeTh r0Q+HY72pmN92aLjJ8eXu/ZCUOA/n9SAVFCTNIEaR1Qlwussy4yBYL7J2YfqkWJf8Xld olCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792103775; x=1792708575; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=tpQG5TITpEcD3UodzKOR9pLgXTFAPmutRocyMUkOoMo=; b=vVuHbEjJsRpP+9x7hrU8m10GrfBYzh6TkF9uVXuXSLkX+FgfKYvlPJraDRuRDlF2rB I1R5OsCHKNIN8AsPflID8zsZUQ/F0z93/5iZ3raAAaQ5LMMkciD/przJJb9hoV1m6u/P mVOlp8MJZEgr1lkgGMN98dGuxH+YuZAO+HsLbhNM2Oxq7WBw/y2h0nF9fywRpAQLBPic 9i+Vf6EdlKUtDsgjrXgJcPX+a7tqLLiowoj2tm2yLvlLHDM1VDKG4+Lur4qBe51wHpqi OyqWOuCFXTbtZcwax4alWTO43nlBMiF7ZkCq0yJ3Q7Xu1Re7QSeqoIjXABKN8eosHXoW qXUg== X-Gm-Message-State: AFq9FYKDAdPU+MnQOElrajLHMG8htIURve3gnawlUCtocZR0SX2zowwx rZmB5RwcgcoTyWbb7iuejELwa3yTqTRXVq4/E9H19pzKgdrHoCnNgLXpsFofWTTN8di/Fw== X-Gm-Gg: AYBFou1flOnoZCPo9GQXCRS0XKIXfClCUm6PebiIVhebDdWkJEuuem0K9JZWGUBzoCU i4IfQEHqRwuGL1nfi/ncVgs2O2g6dZPl7zkuzyYT7x61eK8dF8TKK/VOXDDfUopjCwfQDh9P4I0 HAzc8oNqKv8u6bQPNkNvSS1XSaAxlUjnsXis922fDri93/+4QRx4uEQYH6RyLno0zSmh9sqxUkc QA0K9qlKoIV6RqlGWwYXwTQi5UN4+PcfLJBxa1VhVsijEg9M0sEHz0Z+QuIuaEjCxu9LLfjsOlO iU2emt8BCyynj5Ppqn/llHRl6s6ljANhbZKcfMU6MeeVuIgJrs/LBA34AoXG864bAcyfwrMVWSa wJjtErN7Bs8CbyhYB33VGdDeKa1iqawyGQ5HPe7eJS+W3BPv49+IO0sSgKvgKk+KyRteCacm8M9 40lvAMI+xzD6T2NZUQ6rUNMcvuIpHMemT1+fkurR+KI9QWiWk+N4cjjETtxnBTTx1kA/81orkbc GTUdFnMt31OFmw8uyu7kJap8oAy X-Received: by 2002:a05:6102:418b:b0:7c3:2f13:d905 with SMTP id ada2fe7eead31-7cb3668b831mr7602952137.3.1792103774689; Thu, 15 Oct 2026 15:36:14 -0700 (PDT) Received: from localhost ([2601:19c:4a00:897d:3391:ed89:5571:41a8]) by smtp.gmail.com with ESMTPSA id ada2fe7eead31-7cc198794desm909192137.9.2026.10.15.15.36.14 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Oct 2026 15:36:14 -0700 (PDT) From: Ray Strode To: libcamera-devel@lists.libcamera.org Subject: [PATCH v2 1/4] software-isp: Center the GPU image crop Date: Thu, 15 Oct 2026 18:36:01 -0400 Message-ID: <20261015223604.311616-2-halfline@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261015223604.311616-1-halfline@gmail.com> References: <20261015194335.287960-1-halfline@gmail.com> <20261015223604.311616-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 The GPU debayer path scales the image to fill a requested output size and crops any excess image area. Its projection positions the scaled image against one side of the output, so aspect-ratio changes and Bayer border removal shift the visible scene. The series aligns rendering and metering with a centered sensor crop. This commit centers the projection on the output region in sensor coordinates, distributing the crop across both sides. Signed-off-by: Ray Strode --- .../internal/software_isp/debayer_geometry.h | 41 +++++++++++++++++++ .../internal/software_isp/meson.build | 1 + src/libcamera/software_isp/debayer_egl.cpp | 21 +++------- 3 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 include/libcamera/internal/software_isp/debayer_geometry.h diff --git a/include/libcamera/internal/software_isp/debayer_geometry.h b/include/libcamera/internal/software_isp/debayer_geometry.h new file mode 100644 index 00000000..6c10ecb8 --- /dev/null +++ b/include/libcamera/internal/software_isp/debayer_geometry.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026, Red Hat Inc. + * + * Geometry for scaling and cropping debayered images + */ + +#pragma once + +#include +#include + +#include + +namespace libcamera { + +/* + * Return a column-major projection matrix for an input-sized viewport and an + * output-sized framebuffer. Scale to fill the output, centering the crop on + * the input. All sizes must be nonzero, with nativeSize contained in inputSize. + */ +inline std::array debayerProjection(const Size &inputSize, + const Size &nativeSize, + const Size &outputSize) +{ + float scale = std::max(static_cast(outputSize.width) / nativeSize.width, + static_cast(outputSize.height) / nativeSize.height); + + /* The framebuffer center is output/viewport - 1 in normalized coordinates. */ + float transX = static_cast(outputSize.width) / inputSize.width - 1.0f; + float transY = static_cast(outputSize.height) / inputSize.height - 1.0f; + + return { + scale, 0, 0, 0, + 0, scale, 0, 0, + 0, 0, 1, 0, + transX, transY, 0, 1, + }; +} + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build index df7c3b97..e18597ed 100644 --- a/include/libcamera/internal/software_isp/meson.build +++ b/include/libcamera/internal/software_isp/meson.build @@ -2,6 +2,7 @@ libcamera_internal_headers += files([ 'benchmark.h', + 'debayer_geometry.h', 'debayer_params.h', 'software_isp.h', 'swisp_stats.h', diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 300822f9..1a7ad25c 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -9,7 +9,7 @@ #include "debayer_egl.h" -#include +#include #include #include #include @@ -24,6 +24,7 @@ #include "libcamera/internal/formats.h" #include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/software_isp/debayer_geometry.h" #include "../shaders/glsl_shaders.h" @@ -388,20 +389,8 @@ void DebayerEGL::setShaderVariableValues(eGLImage &eglImageIn, const DebayerPara GLfloat Step[] = { static_cast(bytesPerPixel_) / (inputConfig_.stride - 1), 1.0f / (height_ - 1) }; GLfloat Stride = (GLfloat)width_ / (shaderStridePixels_ / bytesPerPixel_); - /* - * Scale the output size from the native size the algorithm produces for - * the input size. Keep the aspect ratio and prefer cropping over black - * bars. - */ - GLfloat scale = std::max((GLfloat)outputSize_.width / nativeOutputSize_.width, - (GLfloat)outputSize_.height / nativeOutputSize_.height); - GLfloat trans = -(1.0f - scale); - GLfloat projMatrix[] = { - scale, 0, 0, 0, - 0, scale, 0, 0, - 0, 0, 1, 0, - trans, trans, 0, 1 - }; + const std::array projMatrix = + debayerProjection({ width_, height_ }, nativeOutputSize_, outputSize_); /* Static const coordinates */ static const GLfloat vcoordinates[4][2] = { { -1.0f, -1.0f }, @@ -445,7 +434,7 @@ void DebayerEGL::setShaderVariableValues(eGLImage &eglImageIn, const DebayerPara glUniform2fv(textureUniformSize_, 1, imgSize); glUniform2fv(textureUniformStep_, 1, Step); glUniform1f(textureUniformStrideFactor_, Stride); - glUniformMatrix4fv(textureUniformProjMatrix_, 1, GL_FALSE, projMatrix); + glUniformMatrix4fv(textureUniformProjMatrix_, 1, GL_FALSE, projMatrix.data()); LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ << " tex_y " << textureUniformBayerDataIn_ From patchwork Thu Oct 15 22:36:03 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ray Strode X-Patchwork-Id: 28469 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 E6BFEC3316 for ; Thu, 15 Oct 2026 22:36:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E9CFA68E2E; Fri, 16 Oct 2026 00:36:21 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="TE1XqpPK"; dkim-atps=neutral Received: from mail-vk1-xa35.google.com (mail-vk1-xa35.google.com [IPv6:2607:f8b0:4864:20::a35]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 83DFE68E1F for ; Fri, 16 Oct 2026 00:36:17 +0200 (CEST) Received: by mail-vk1-xa35.google.com with SMTP id 71dfb90a1353d-5e9528732b4so3311916e0c.0 for ; Thu, 15 Oct 2026 15:36:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792103776; x=1792708576; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=d0ZIPEqnqMbbVlotQ+4T3vD1D97n+6qK2eVOnrf5BaI=; b=TE1XqpPK69w3Lp8G1ujpsrIgzYN9CxoczdcrKi2Cgz/B9R6A1wEsxrxBT0+R1uz8y1 gx9bV1x+uvhO3XukHb37sjHoc+E6H2Zu4c3d7EFOyszqQJ+c2MbKJ+6Mxys6rGt9KytO +7Ny4DVDs1yVS9QnwO8INpvxgCQiK8kkjsZ7QFc6nH4DS2wfh12kn2Y7+Wu8TKjIU1oT acQQ3GtPiTr2wkztwiil74WxrKQ7WszxDYQfFp3LSIogUqYWYwM4TZDroFCAQpVqFyGA CJQ2y13MOVfHC3B64nWtATYgIZA1Vyz9GVKuQi7GsgbAEaiIVgKbofKbh3JdnMCJMGeR PmcQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792103776; x=1792708576; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=d0ZIPEqnqMbbVlotQ+4T3vD1D97n+6qK2eVOnrf5BaI=; b=rVPxCPscVbgo+/uqI4Jc16LqtBQ0KhjatVgZfzxr0DULToDFLlYc9IHem+ZalHtI43 v1ObfiFWy7t6fdzvLOkkShkA+cyorQx2GZQV4R5gksSjyXVbbTliWrg3vaktXBc+ERMs p6qTRlysZJ1KP8YQNUcKOxWsVM0bRhf09//3+6sWeRKugOHyQyHYKwntpX55S7lsDC6Y oZT3QHwo8JujXIaXyE/nbC082eevsJ9vrglnAEBs5KTOcsjeSpY0AGqNHMhuDCiTz2Gu fvHYpz6arCn89GD8KO98GgVXn6usmMSBZyCA6Z0xxplMM2f3F4RG9fmimgDLxQLA0Odk toZA== X-Gm-Message-State: AFq9FYIIn4dkEJ2PX0oOqmH5t7coWnWY+3Q+Rj3mGED2UH4Pv50hjxkl Wjj2RcsMimPou7JuRZ4OHXJAOs9OgVZ44kGpCnXu7enohHOBaKIXtlEiT8tUKftbS7Ic1A== X-Gm-Gg: AYBFou0G7VPrEWm++HlYhY35F5rQAZDRUYB3g6FaLZotM22RdY7TARvzwNauy4aNfAt tboYC6UrsCRKJSPOpSN1eJxxsKlEpu7UMvBf26nlD3pIAd0GXXVbF0RiEIhNcoPMJ5uajWhiT8F Ic+pK9h80hxf8uIlj1Vp9jCPHQ7Mnm8P924BYW6pxv6TTKRWOFfPvmic+JKfwDnaVRhazR/5YOQ 9w/2nCf6zH9nR0OU1po7ajGmbd7M+eqA2M5Q9D9vKWtAs6P7g8yxE9F97xahxJB9jDs2XOGI0c/ hh4ZVxxBjWXl1NJN2rqFWbscaYErYzKtdLjimS6uBrl5JTSJK2+uXAx84W6/SXXL2VrXyO4yeQ0 8EGHNFZA5CZqqjm/Z+5A1B23TpjTcaDQTbZ9Fuw21VpotrLqPKADhMQyCH5y86DcKq/FQ5/2TNu nSyFlgZ+sN2xCbjvZJUEXcKxvqLdi5jcFzQ3FgTJEowkWRRm77H/MMWVe6qb+bmenA76prYF6Ms JtgPc43w2sN4hEytBwtyyq0NhNR X-Received: by 2002:a05:6102:149d:b0:7a7:ad9f:53e2 with SMTP id ada2fe7eead31-7cb36987a53mr7848502137.1.1792103776290; Thu, 15 Oct 2026 15:36:16 -0700 (PDT) Received: from localhost ([2601:19c:4a00:897d:3391:ed89:5571:41a8]) by smtp.gmail.com with ESMTPSA id ada2fe7eead31-7cc198794desm909192137.9.2026.10.15.15.36.15 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Oct 2026 15:36:15 -0700 (PDT) From: Ray Strode To: libcamera-devel@lists.libcamera.org Subject: [PATCH v2 3/4] software-isp: Meter the visible sensor crop Date: Thu, 15 Oct 2026 18:36:03 -0400 Message-ID: <20261015223604.311616-4-halfline@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261015223604.311616-1-halfline@gmail.com> References: <20261015194335.287960-1-halfline@gmail.com> <20261015223604.311616-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 The GPU debayer path draws a centered sensor crop into the requested output size, while CPU statistics read the original input buffer. The statistics window still follows the output dimensions, so metering covers a different part of the sensor when output sizes or aspect ratios change. This commit derives the visible crop in sensor coordinates and centers the statistics window on that region. Signed-off-by: Ray Strode --- .../internal/software_isp/debayer_geometry.h | 8 ++++++++ src/libcamera/software_isp/debayer_egl.cpp | 13 +++---------- src/libcamera/software_isp/debayer_egl.h | 1 - 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/libcamera/internal/software_isp/debayer_geometry.h b/include/libcamera/internal/software_isp/debayer_geometry.h index 6c10ecb8..c6359cde 100644 --- a/include/libcamera/internal/software_isp/debayer_geometry.h +++ b/include/libcamera/internal/software_isp/debayer_geometry.h @@ -38,4 +38,12 @@ inline std::array debayerProjection(const Size &inputSize, }; } +/* Return the visible sensor rectangle, before statistics Bayer alignment. */ +inline Rectangle debayerCrop(const Size &inputSize, const Size &nativeSize, + const Size &outputSize) +{ + const Size visibleSize = nativeSize.boundedToAspectRatio(outputSize); + return visibleSize.centeredTo(Rectangle(inputSize).center()); +} + } /* namespace libcamera */ diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 1a7ad25c..9f3dc752 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -323,18 +323,11 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg, outputSize_ = outputCfg.size; nativeOutputSize_ = outSizeRange.max; - window_.x = ((inputCfg.size.width - outputCfg.size.width) / 2) & - ~(inputConfig_.patternSize.width - 1); - window_.y = ((inputCfg.size.height - outputCfg.size.height) / 2) & - ~(inputConfig_.patternSize.height - 1); - window_.width = outputCfg.size.width; - window_.height = outputCfg.size.height; - /* - * Don't pass x,y from window_ since process() already adjusts for it. - * But crop the window to 2/3 of its width and height for speedup. + * The GPU scales the visible sensor crop to outputSize_. Statistics + * consume the original input buffer, so use sensor coordinates here. */ - stats_->setWindow(Rectangle(window_.size())); + stats_->setWindow(debayerCrop(inputCfg.size, nativeOutputSize_, outputSize_)); inputBufferCount_ = inputCfg.bufferCount; outputBufferCount_ = outputCfg.bufferCount; diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index 30e51a47..52b8aa07 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -111,7 +111,6 @@ private: GLint contrastExpUniformDataIn_; Size nativeOutputSize_; - Rectangle window_; std::unique_ptr stats_; eGL egl_; uint32_t width_; From patchwork Thu Oct 15 22:36:04 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ray Strode X-Patchwork-Id: 28470 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 F3CD5C3357 for ; Thu, 15 Oct 2026 22:36:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E33FE68E1F; Fri, 16 Oct 2026 00:36:22 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="dvyA1RfV"; dkim-atps=neutral Received: from mail-vs1-xe2b.google.com (mail-vs1-xe2b.google.com [IPv6:2607:f8b0:4864:20::e2b]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 95F6768E1C for ; Fri, 16 Oct 2026 00:36:18 +0200 (CEST) Received: by mail-vs1-xe2b.google.com with SMTP id ada2fe7eead31-7c420c2c4faso3785758137.1 for ; Thu, 15 Oct 2026 15:36:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792103777; x=1792708577; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=baHwsbZhar5+TW7IU/+ueixmwWLl9jAPh4Ih8iGpoLc=; b=dvyA1RfVpao/5te/mLE1NuxFSmhOfZc7WI0RZdR12sCKMmZ6Zz//pQm9GxsULa88/E YkPq7mW7RLKWZ/MXckdKLkDc93LrRxsJN11NNfOZ3Lso6/HYWpt+sY1zkgEv2c2WLHBT cG7f4YNXG3/H6lwL9EHQ1srdantUQD8uAww2RXrPZIlkr+lgxCUSzPAfmCWkPmV+14r5 KCg6HhRBBC1G2xd/JSiOhvPth9+rGngIhmaPameACl3S1DSKdfKFsvMdEgYNjWpWGRYw aToaiX15rl/OsA3tZoaRxF74ZYtziHqt2whIPpn4Ay8v/+lgcZSi4Qn7nzZ13Jx5ye3y TfCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792103777; x=1792708577; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=baHwsbZhar5+TW7IU/+ueixmwWLl9jAPh4Ih8iGpoLc=; b=meonXtxTVT2YjT6nN2ys+NKZLqvz2No1SAWIwoDZdC6/5gLILXtluaXuELiHQfyKaE 7ppZUqSuhiQEvXxhjfiVku7ISVCQ+5HFRttpqDgpMdc1/O5SHd2z09S4YtE5OI+ziXLW /HKOGA3LKds2oIiQxG/5a4LbOR6LBCB8HsjVEs/b+0vjO/+JrzZtefswYwkoX7ERJ58y ixy2tUi1ysmMshpvugF4+ZY1Z+8trFES8WIuBm7U0edhkhQJA7yoR6Fpbngkl0OX+NSR ZYo5FTkuIsCmYcK8mkiHHIqYRJRgzSX4dPm4PRaimcrNnwKgUTn1pDObhuZ14mnftFqW tafw== X-Gm-Message-State: AFq9FYISDvN2JH1a6O5VdOn2LFGIuWAETBXYu91RmBhCFo5sKam7XZFO LE33IQOFzKd0zAmH6T4qqRuf+2dBPWB4eF/6zkzrST7wFO9oSu+0PXdH+gPDUEtufva0MQ== X-Gm-Gg: AYBFou2GvRSwI+CaSY2Dmc1MKfxL7qINI2NppoGKhdB9OJck0pFj9A0pANB9sc051Gi zs2PRP/8SYPwIZaQcn1QP0+dr3fUBJyD0I/cq5Vgxd7NjmO0oKW4x/InxIxNOSF3yXoZonq77VA 4XgLd174qaBpZaT9AhGsWXXFto6/rVaWO5xcA7MHGnboTxs59eTsjkfzf9hMQPD/FSae+7yF7Zw xGicT7APVRLiiUGvgnBt6bAmZt2L+HpbtwKjT6DJ4MIAixwjXhftBWLPSleg4J+MKHkNCMUCOI/ vYPa+ogyLefkWaWK+1RBz9pnmI9IlslYgvMtcXVZf8IDDlZvY7qM7yWQKaA8Co7EYS/mk/e1t8i AoGdu/NwvxSQLOKlvXfk/QkmXakrjrYOVda/lButDuy3h7qj4tZ9GGez2laLYvBdTEWAGVJWggz 0wWpDUsgvmtDKvRtwChxVOTiwOCpFvlQ8ImrgvufX0YInVBlO3EYJ7CEBVeilg8l+VDRy4NKiC8 jH1mQz2ikmGK9ZjwiBpNHfTtA+q X-Received: by 2002:a05:6102:448c:b0:7c3:99a3:314a with SMTP id ada2fe7eead31-7cb3729b087mr7508083137.9.1792103777134; Thu, 15 Oct 2026 15:36:17 -0700 (PDT) Received: from localhost ([2601:19c:4a00:897d:3391:ed89:5571:41a8]) by smtp.gmail.com with ESMTPSA id ada2fe7eead31-7cc198794desm909192137.9.2026.10.15.15.36.16 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Oct 2026 15:36:16 -0700 (PDT) From: Ray Strode To: libcamera-devel@lists.libcamera.org Subject: [PATCH v2 4/4] tests: Validate the visible sensor crop Date: Thu, 15 Oct 2026 18:36:04 -0400 Message-ID: <20261015223604.311616-5-halfline@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261015223604.311616-1-halfline@gmail.com> References: <20261015194335.287960-1-halfline@gmail.com> <20261015223604.311616-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 The GPU debayer path selects its statistics window from the visible sensor crop. The geometry unit test checks the projection used for rendering. The project lacks a direct check that the sensor crop remains centered and follows the output aspect ratio without shrinking to the output resolution. This commit extends the 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 | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/test/debayer-geometry.cpp b/test/debayer-geometry.cpp index 8719b9f5..706a4971 100644 --- a/test/debayer-geometry.cpp +++ b/test/debayer-geometry.cpp @@ -2,7 +2,7 @@ /* * Copyright (C) 2026, Red Hat Inc. * - * Debayer projection tests + * Debayer projection and sensor crop tests */ #include @@ -23,7 +23,7 @@ class DebayerGeometryTest : public Test protected: int run() override { - if (testProjection()) + if (testProjection() || testCrop()) return TestFail; return TestPass; @@ -93,6 +93,37 @@ private: return TestPass; } + 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)