From patchwork Wed Sep 2 19:15:54 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Neiva de Carvalho X-Patchwork-Id: 28178 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 74B7AC3348 for ; Wed, 2 Sep 2026 20:04:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4B0DE685E4; Wed, 2 Sep 2026 22:04:34 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="kyCkl/fW"; 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 180CA685CC for ; Wed, 2 Sep 2026 21:16:13 +0200 (CEST) Received: by mail-ua1-x934.google.com with SMTP id a1e0cc1a2514c-97bf8f6a31eso558862241.1 for ; Wed, 02 Sep 2026 12:16:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788376572; x=1788981372; 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=8kt0mrOlzLzzldA/TB1pVNyPk4PXIcCqxuuviWAZGXc=; b=kyCkl/fWYjUwUQ00TYgp2YEkeAC27YWbX/XBGlkgYTri5D8zSQMJyqbWzK+Noaamf6 ZJdJGm6YOhDB7kE7TEtrMkT0GniIs6FDdDZ9OSkm1uuBqPNoqbs1DhK2jDd0JPUh46de ZfKE3iKHP6EtBAoDz+XOncL0QZ1mioacCwPB8jyRy0BIp2Ta/qsvgHxY36O7wbyxky/j HsIy+UUsJFDbY5qzN6LlEIDWVXQGxX8A4Ubf0qhD5gGNlSOmE2QEy0mXzu5rSWM7kU4s psrIHSbCyA9NFKtzclTZT2iUUzBvAwqki3YSTOntgOiTmNMjNNyh2x4PQuSi4MAAj4vq tnrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788376572; x=1788981372; 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=8kt0mrOlzLzzldA/TB1pVNyPk4PXIcCqxuuviWAZGXc=; b=scRhD5KOCG51s+bqjiAWWO0WBATulHjmCgo95VRHqZYQ0oqbyuxqSXJUjtY5nyzYa9 SHHXUmPjU/IxPr0atccgrRH2JBLKgJNepgX9Qvf7SWAlBO1FUqQKXb8bta/mQLCqnaOe RgENbR0cUh5WGydSM1Jptb/uAFuhoQGIiJJ45pMxvPV52nOrUVTGeM3R6x9IgCKP8Ojg tuZKFvwldV1nYIdtjKCsk1otWO41j8/QAhF64XaFJOwxrskRZWISFWmWkuv2fn+nkW9p MSWP8yC51lxFMDJ+U7bWRSwrU6MaKTviDQSjd3Qb/ZWa+Tn5JhNhnzJ/4Sdux20Nnopn WfUw== X-Gm-Message-State: AFuF++m/BfrJ9t2E637DYgQ7+m3inwUMYPy7GTUgqHfIjC7FngDAuVuR +cSgiuP+BPG9XlqPZ8cJyys/x7Fg7Y9CtRZMdSK/zpetnFOHhNaTAneX3YXFtEX1ftM= X-Gm-Gg: AYBFou0qdAPU0+xGfeNx/N+jVL+g9ZQZuub4QdCyGY0XjcnjoDxcAwWrqsGwMhPefUI NxS3qLpQlHE1CbVrppI7z/qLcO6tzgk6/dtYwQE0vzUNr/3xWSUVfb4KeAPE/FCoqHL+EFfYZJ0 TiziRci4ypzyBCDqwqeYHHUafWwvZBvNCXMVKqlKVWrMFdCp97mF1XE2szE4pMyMuWgtiqYcAIh 6w/MFPC/u6RMkg73QXVrQU/UcIECmwJmk8+EZW1GT16CIydbL9b90NkPu1eSDvzT3nliWR9913T XyfNdcRL2QDoB6GXfNBaEGGaRLxYde6GLAPjz3DxZJmc1riQG9BKX4AW2+U3quHw7JIH04hsGf0 pmCyauPmwjS4shYRaTjuZw1x6EASWga5NkDLtHMernLRv9I7cEDH1ZSlSOn5L5j4ArqF7o5VW+h NgBCJznI7UbNH7Km2/req5AC2uHr3+OHV3fOKLqH3ujWMjtUGUbJkLl6ioZ/0= X-Received: by 2002:a05:6102:524a:b0:77c:dbae:f9d2 with SMTP id ada2fe7eead31-78a1f2df7a6mr2094212137.9.1788376571801; Wed, 02 Sep 2026 12:16:11 -0700 (PDT) Received: from laptop ([45.184.68.165]) by smtp.gmail.com with ESMTPSA id ada2fe7eead31-78a1a1feac0sm3003754137.2.2026.09.02.12.16.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Sep 2026 12:16:11 -0700 (PDT) From: Martin Neiva de Carvalho To: libcamera-devel@lists.libcamera.org Cc: Martin Neiva de Carvalho Subject: [PATCH 5/5] libcamera: software_isp: Centre the crop the GPU debayer applies Date: Wed, 2 Sep 2026 16:15:54 -0300 Message-ID: <20260902191554.84922-6-martincarvalho@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260902191554.84922-1-martincarvalho@gmail.com> References: <20260902191554.84922-1-martincarvalho@gmail.com> MIME-Version: 1.0 X-Mailman-Approved-At: Wed, 02 Sep 2026 22:04:26 +0200 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" A stream whose aspect ratio differs from the sensor's cannot show all of it, and cropping the sides is the right answer - black bars would be worse. But the crop has to be taken from both sides. The viewport is sized from the sensor frame while the buffer being drawn into is the size the application asked for, so that buffer covers only the corner of the viewport running from NDC -1 to where its own width reaches. Translating the quad by -(1 - scale) puts the texture's left and bottom edges exactly at that corner, so everything cropped comes off one side. Measured on an OV02C10 by registering a 640x480 stream against a 1920x1080 one of the same scene - searching for the scale and offset that maximise the normalised correlation between them - the smaller stream showed a 1391x1043 window of the sensor's 1920x1080, starting at (48, 22). Centring the 4:3 window in the 16:9 frame calls for 1440x1080 starting at (240, 0). A subject had to sit a sixth of a frame off centre to appear centred, and the framing moved whenever the application chose a different resolution. Translate to the middle of the region the buffer actually covers instead. That region spans NDC -1 to 2 * out / viewport - 1, so its midpoint is out / viewport - 1. The same measurement then reports 1438x1079 starting at (243, 0), which is the centred window to within the three pixels the registration can resolve. At the native size this shares the eight columns and twelve rows of Bayer border between the two edges rather than taking them all off one, moving the picture by half a border. Nothing is resampled: the viewport and the scale factor are untouched. Signed-off-by: Martin Neiva de Carvalho --- src/libcamera/software_isp/debayer_egl.cpp | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index c042d3864..0ccae473f 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -388,16 +388,33 @@ void DebayerEGL::setShaderVariableValues(eGLImage &eglImageIn, const DebayerPara /* * 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. + * bars - but crop from both sides, not from one. + * + * The viewport is the sensor frame while the buffer drawn into is the + * requested size, so the buffer covers only the corner of the viewport + * that starts at NDC -1 and ends where its own width reaches. Placing + * the quad at -(1 - scale) puts the texture's left edge exactly at + * that corner, so everything cropped is taken off one side: metered + * by registering a 640x480 stream against a 1920x1080 one of the same + * scene, the frame shown ran from x=48 rather than from the x=240 + * that centring the 4:3 window in a 16:9 sensor calls for. + * + * Centre it on the region the buffer actually covers instead. That + * region spans NDC -1 to 2*out/viewport - 1, whose midpoint is + * out/viewport - 1, and putting the quad's centre there splits the + * crop evenly between the two edges at every size, the native one + * included - where it shares the eight columns of Bayer border + * instead of taking them all off the right. */ GLfloat scale = std::max((GLfloat)outputSize_.width / nativeOutputSize_.width, (GLfloat)outputSize_.height / nativeOutputSize_.height); - GLfloat trans = -(1.0f - scale); + GLfloat transX = (GLfloat)outputSize_.width / width_ - 1.0f; + GLfloat transY = (GLfloat)outputSize_.height / height_ - 1.0f; GLfloat projMatrix[] = { scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1, 0, - trans, trans, 0, 1 + transX, transY, 0, 1 }; /* Static const coordinates */ static const GLfloat vcoordinates[4][2] = {