[{"id":37364,"web_url":"https://patchwork.libcamera.org/comment/37364/","msgid":"<d3978548-f0b5-439f-82b8-51e824682666@collabora.com>","date":"2025-12-14T13:34:24","subject":"Re: [PATCH v8 14/26] libcamera: software_isp: debayer_egl: Add an\n\teGL Debayer class","submitter":{"id":140,"url":"https://patchwork.libcamera.org/api/people/140/","name":"Robert Mader","email":"robert.mader@collabora.com"},"content":"Hi\n\nOn 12.12.25 01:29, Bryan O'Donoghue wrote:\n> ...\n> +}\n> +\n> +void DebayerEGL::setShaderVariableValues(DebayerParams &params)\n> +{\n> +\t/*\n> +\t * Raw Bayer 8-bit, and packed raw Bayer 10-bit/12-bit formats\n> +\t * are stored in a GL_LUMINANCE texture. The texture width is\n> +\t * equal to the stride.\n> +\t */\n> +\tGLfloat firstRed[] = { firstRed_x_, firstRed_y_ };\n> +\tGLfloat imgSize[] = { (GLfloat)width_,\n> +\t\t\t      (GLfloat)height_ };\n> +\tGLfloat Step[] = { static_cast<float>(bytesPerPixel_) / (inputConfig_.stride - 1),\n> +\t\t\t   1.0f / (height_ - 1) };\n> +\tGLfloat Stride = (GLfloat)width_ / (shaderStridePixels_ / bytesPerPixel_);\n> +\tGLfloat scaleX = (GLfloat)window_.width / width_;\n> +\tGLfloat scaleY = (GLfloat)window_.height / height_;\n> +\tGLfloat transX = -(1.0f - scaleX);\n> +\tGLfloat transY = -(1.0f - scaleY);\n> +\tGLfloat scale = std::max(scaleX, scaleY);\n> +\tGLfloat projMatrix[] = {\n> +\t\tscale, 0, 0, 0,\n> +\t\t0, scale, 0, 0,\n> +\t\t0, 0, 1, 0,\n> +\t\ttransX, transY, 0, 1\n> +\t};\n\nI made a small cleanup for this to make it easier to understand - mind \ncherry-picking / squashing (and adopting as you see fit) \nhttps://gitlab.freedesktop.org/rmader/libcamera/-/commit/53d61543dfaa5ee0b06e189e701e9319d5c38eca \n?","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 36BF8C3257\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 14 Dec 2025 13:34:36 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2C36E61939;\n\tSun, 14 Dec 2025 14:34:35 +0100 (CET)","from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com\n\t[136.143.188.112])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BF47B61613\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 14 Dec 2025 14:34:33 +0100 (CET)","by mx.zohomail.com with SMTPS id 1765719268484257.524809279852;\n\tSun, 14 Dec 2025 05:34:28 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=collabora.com\n\theader.i=robert.mader@collabora.com header.b=\"R6UUHl1t\"; \n\tdkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1765719270; cv=none; \n\td=zohomail.com; s=zohoarc; \n\tb=DUv3Vh5tDFhr0yWDyBvtnqJxSTK6ycBH4fjRxcXGE+hRu2od6P0fYilndqc69S6dcdjgKwXmWlBeVyxyKiEg0jgvTxnPACS++GfWnYqQNF9mvjkok9wFTkF2XzBBihvuMWc5D3M/txUnGwbEWG8YO8t+txdLJ/LKe3ZfoOXQFIc=","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; \n\ts=zohoarc; t=1765719270;\n\th=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To;\n\tbh=xq8QUUjZqRfCT7ixGNfYP48wtFkcx/WvISn1z/e2EBc=; \n\tb=UlVGToFKVtXJj8MgOJFppzAzTJzNCXlpJsIOZukyqC2/Hv4JtvcoPgMdc6Tv+WOx4EjcxxpskkijPCQ7usB86uJrIsS6Ey8rmeJ2nNr7dldx2UpWT+p5Wzp/DaVcYruK+rDGOWwISCfqRmafhUHPLJ4+eLsXViJWDeLYK7HmvvI=","ARC-Authentication-Results":"i=1; mx.zohomail.com;\n\tdkim=pass  header.i=collabora.com;\n\tspf=pass  smtp.mailfrom=robert.mader@collabora.com;\n\tdmarc=pass header.from=<robert.mader@collabora.com>","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1765719270;\n\ts=zohomail; d=collabora.com; i=robert.mader@collabora.com;\n\th=Message-ID:Date:Date:MIME-Version:Subject:Subject:To:To:Cc:Cc:References:From:From:In-Reply-To:Content-Type:Content-Transfer-Encoding:Message-Id:Reply-To;\n\tbh=xq8QUUjZqRfCT7ixGNfYP48wtFkcx/WvISn1z/e2EBc=;\n\tb=R6UUHl1taEfds8SM6WXRSmlAWD20ARvHlRXiruwHHb8SWdICO4QGD+l8fHvL4Qj+\n\t1RGHr9pGbhQJR3NyaYUmD8Eta2gGvDvYzbN4thAqs2o2GtqBmYSggUrmdJkQv4dlG7R\n\tTCMojCPdN3sLdQ+ODs2jFFMRLnAwl2HEwsC7Vavo=","Message-ID":"<d3978548-f0b5-439f-82b8-51e824682666@collabora.com>","Date":"Sun, 14 Dec 2025 14:34:24 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v8 14/26] libcamera: software_isp: debayer_egl: Add an\n\teGL Debayer class","To":"Bryan O'Donoghue <bryan.odonoghue@linaro.org>,\n\tlibcamera-devel@lists.libcamera.org","Cc":"pavel@ucw.cz, Milan Zamazal <mzamazal@redhat.com>","References":"<20251212002937.3118-1-bryan.odonoghue@linaro.org>\n\t<20251212002937.3118-15-bryan.odonoghue@linaro.org>","Content-Language":"en-US, de-DE, en-GB","From":"Robert Mader <robert.mader@collabora.com>","In-Reply-To":"<20251212002937.3118-15-bryan.odonoghue@linaro.org>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"7bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":37365,"web_url":"https://patchwork.libcamera.org/comment/37365/","msgid":"<4b282c8f-ff6b-4924-a9cd-f6bd29d56314@collabora.com>","date":"2025-12-14T14:02:53","subject":"Re: [PATCH v8 14/26] libcamera: software_isp: debayer_egl: Add an\n\teGL Debayer class","submitter":{"id":140,"url":"https://patchwork.libcamera.org/api/people/140/","name":"Robert Mader","email":"robert.mader@collabora.com"},"content":"Pardon, added another small cleanup - so I suggest/ask to cherry-pick \nthe commit \"debayer_egl: Small cleanup for projection calculation\" from \nhttps://gitlab.freedesktop.org/rmader/libcamera/-/commits/0.6.0-gpuisp-v9-fixes\n\nOn 14.12.25 14:34, Robert Mader wrote:\n> Hi\n>\n> On 12.12.25 01:29, Bryan O'Donoghue wrote:\n>> ...\n>> +}\n>> +\n>> +void DebayerEGL::setShaderVariableValues(DebayerParams &params)\n>> +{\n>> +    /*\n>> +     * Raw Bayer 8-bit, and packed raw Bayer 10-bit/12-bit formats\n>> +     * are stored in a GL_LUMINANCE texture. The texture width is\n>> +     * equal to the stride.\n>> +     */\n>> +    GLfloat firstRed[] = { firstRed_x_, firstRed_y_ };\n>> +    GLfloat imgSize[] = { (GLfloat)width_,\n>> +                  (GLfloat)height_ };\n>> +    GLfloat Step[] = { static_cast<float>(bytesPerPixel_) / \n>> (inputConfig_.stride - 1),\n>> +               1.0f / (height_ - 1) };\n>> +    GLfloat Stride = (GLfloat)width_ / (shaderStridePixels_ / \n>> bytesPerPixel_);\n>> +    GLfloat scaleX = (GLfloat)window_.width / width_;\n>> +    GLfloat scaleY = (GLfloat)window_.height / height_;\n>> +    GLfloat transX = -(1.0f - scaleX);\n>> +    GLfloat transY = -(1.0f - scaleY);\n>> +    GLfloat scale = std::max(scaleX, scaleY);\n>> +    GLfloat projMatrix[] = {\n>> +        scale, 0, 0, 0,\n>> +        0, scale, 0, 0,\n>> +        0, 0, 1, 0,\n>> +        transX, transY, 0, 1\n>> +    };\n>\n> I made a small cleanup for this to make it easier to understand - mind \n> cherry-picking / squashing (and adopting as you see fit) \n> https://gitlab.freedesktop.org/rmader/libcamera/-/commit/53d61543dfaa5ee0b06e189e701e9319d5c38eca \n> ?\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 0FDD6BD1F1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 14 Dec 2025 14:03:06 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 45DCB61931;\n\tSun, 14 Dec 2025 15:03:05 +0100 (CET)","from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com\n\t[136.143.188.112])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5124161613\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 14 Dec 2025 15:03:03 +0100 (CET)","by mx.zohomail.com with SMTPS id 1765720977231539.3588044003195;\n\tSun, 14 Dec 2025 06:02:57 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=collabora.com\n\theader.i=robert.mader@collabora.com header.b=\"UmYZbfQi\"; \n\tdkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1765720978; cv=none; \n\td=zohomail.com; s=zohoarc; \n\tb=EgknQnxdBQRosbZTS1r5BaANENULOkztLhE5Mo/z7Vbn/tsTYgYBQFOnFPA00EZAO1fFdaJzLXgUMhX64jTkIN7WTQWoRqEhCEBBSK/a93ERjOj6gI/3nIC8+2zc6xSstA3jRI6LNZlytNwIXGH1Q8F+YkAM2CRiLbui+RWcbgI=","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; \n\ts=zohoarc; t=1765720978;\n\th=Content-Type:Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To:Cc;\n\tbh=BP8HXnh1OHRp0e3wx5xEXl5TkHaKBsFv4x8TlSiyiCg=; \n\tb=JNofcZshqhD7UU9Ea72GmkjZBqGLyBnrEQq8BH5XeG6dT8J6LM77f3vrYAuU3C4ekwgHdLvPOJEoGr8XuKc3RiQ/ZEXGT+z7AeZVlNxNEyawv7TablpQ3YOpBrnHAGQ59vQCjNal8jxRGyNinid+OQ7Jo24Kbw8xFBPLqRF/8yI=","ARC-Authentication-Results":"i=1; mx.zohomail.com;\n\tdkim=pass  header.i=collabora.com;\n\tspf=pass  smtp.mailfrom=robert.mader@collabora.com;\n\tdmarc=pass header.from=<robert.mader@collabora.com>","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1765720978;\n\ts=zohomail; d=collabora.com; i=robert.mader@collabora.com;\n\th=Message-ID:Date:Date:MIME-Version:Subject:Subject:To:To:References:From:From:In-Reply-To:Content-Type:Content-Transfer-Encoding:Message-Id:Reply-To:Cc;\n\tbh=BP8HXnh1OHRp0e3wx5xEXl5TkHaKBsFv4x8TlSiyiCg=;\n\tb=UmYZbfQiKEVazuSb/oyLYhGhr0B/lCDoBjHk3h5Dj78Tme90z3DzRDKVYdm7/xs+\n\tL9pOkCY8Y6/FAdGPgQy1tOto79YzMRvcLa3pl/q6xoY2aeO0fqQzyqBpc5yHD+wvc8/\n\tbEMF40Rkn25u/zSJW0wWxbClI+1lD25HAAL34PHU=","Message-ID":"<4b282c8f-ff6b-4924-a9cd-f6bd29d56314@collabora.com>","Date":"Sun, 14 Dec 2025 15:02:53 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v8 14/26] libcamera: software_isp: debayer_egl: Add an\n\teGL Debayer class","To":"libcamera-devel@lists.libcamera.org","References":"<20251212002937.3118-1-bryan.odonoghue@linaro.org>\n\t<20251212002937.3118-15-bryan.odonoghue@linaro.org>\n\t<d3978548-f0b5-439f-82b8-51e824682666@collabora.com>","Content-Language":"en-US, de-DE, en-GB","From":"Robert Mader <robert.mader@collabora.com>","In-Reply-To":"<d3978548-f0b5-439f-82b8-51e824682666@collabora.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":37398,"web_url":"https://patchwork.libcamera.org/comment/37398/","msgid":"<851pkvcxij.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2025-12-15T20:15:16","subject":"Re: [PATCH v8 14/26] libcamera: software_isp: debayer_egl: Add an\n\teGL Debayer class","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Some usual cosmetic issues:\n\nBryan O'Donoghue <bryan.odonoghue@linaro.org> writes:\n\n> Add a class to run the existing glsl debayer shaders on a GBM surface.\n>\n> Signed-off-by: Robert Mader <robert.mader@collabora.com>\n> Co-developed-by: Robert Mader <robert.mader@collabora.com>\n> [bod: took scaling and buffer size fixes from Robert]\n> [bod: took fix for center byte calculation from Hans]\n> [bod: took formatting fixes from Milan]\n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> Co-developed-by: Milan Zamazal <mzamazal@redhat.com>\n> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>\n> ---\n>  src/libcamera/software_isp/debayer_egl.cpp | 641 +++++++++++++++++++++\n>  src/libcamera/software_isp/debayer_egl.h   | 142 +++++\n>  src/libcamera/software_isp/meson.build     |   8 +\n>  3 files changed, 791 insertions(+)\n>  create mode 100644 src/libcamera/software_isp/debayer_egl.cpp\n>  create mode 100644 src/libcamera/software_isp/debayer_egl.h\n>\n> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> new file mode 100644\n> index 000000000..cae7cb227\n> --- /dev/null\n> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> @@ -0,0 +1,641 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024, Linaro Ltd.\n> + *\n> + * Authors:\n> + * Bryan O'Donoghue <bryan.odonoghue@linaro.org>\n> + *\n> + * debayer_cpu.cpp - EGL based debayering class\n\nNo file name.\n\n> + */\n> +\n> +#include \"debayer_egl.h\"\n> +\n> +#include <math.h>\n> +#include <stdlib.h>\n> +#include <time.h>\n> +\n> +#include <libcamera/base/utils.h>\n> +\n> +#include <libcamera/formats.h>\n> +\n> +#include \"../glsl_shaders.h\"\n> +\n> +namespace libcamera {\n> +\n> +/**\n> + * \\class DebayerEGL\n> + * \\brief Class for debayering using an EGL Shader\n> + *\n> + * Implements an EGL shader based debayering solution.\n> + */\n> +\n> +/**\n> + * \\fn DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const GlobalConfiguration &configuration)\n> + * \\brief Construct a DebayerEGL object\n> + * \\param[in] stats Statistics processing object\n> + * \\param[in] configuration Global configuration reference\n> + */\n> +DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const GlobalConfiguration &configuration)\n> +\t: Debayer(configuration), stats_(std::move(stats)) {}\n\nThe formatter says it should be\n\n  : Debayer(configuration), stats_(std::move(stats))\n  {\n  }\n\n> +\n> +DebayerEGL::~DebayerEGL() {}\n\nSimilarly here.\n\n> +\n> +int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config)\n> +{\n> +\tBayerFormat bayerFormat =\n> +\t\tBayerFormat::fromPixelFormat(inputFormat);\n> +\n> +\tif ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10) &&\n> +\t    bayerFormat.packing == BayerFormat::Packing::None &&\n> +\t    isStandardBayerOrder(bayerFormat.order)) {\n> +\t\tconfig.bpp = (bayerFormat.bitDepth + 7) & ~7;\n> +\t\tconfig.patternSize.width = 2;\n> +\t\tconfig.patternSize.height = 2;\n> +\t\tconfig.outputFormats = std::vector<PixelFormat>({ formats::XRGB8888,\n> +\t\t\t\t\t\t\t\t  formats::ARGB8888,\n> +\t\t\t\t\t\t\t\t  formats::XBGR8888,\n> +\t\t\t\t\t\t\t\t  formats::ABGR8888 });\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tif (bayerFormat.bitDepth == 10 &&\n> +\t    bayerFormat.packing == BayerFormat::Packing::CSI2 &&\n> +\t    isStandardBayerOrder(bayerFormat.order)) {\n> +\t\tconfig.bpp = 10;\n> +\t\tconfig.patternSize.width = 4; /* 5 bytes per *4* pixels */\n> +\t\tconfig.patternSize.height = 2;\n> +\t\tconfig.outputFormats = std::vector<PixelFormat>({ formats::XRGB8888,\n> +\t\t\t\t\t\t\t\t  formats::ARGB8888,\n> +\t\t\t\t\t\t\t\t  formats::XBGR8888,\n> +\t\t\t\t\t\t\t\t  formats::ABGR8888 });\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tLOG(Debayer, Error)\n> +\t\t<< \"Unsupported input format \" << inputFormat.toString();\n> +\n> +\treturn -EINVAL;\n> +}\n> +\n> +int DebayerEGL::getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config)\n> +{\n> +\tif (outputFormat == formats::XRGB8888 || outputFormat == formats::ARGB8888 ||\n> +\t    outputFormat == formats::XBGR8888 || outputFormat == formats::ABGR8888) {\n> +\t\tconfig.bpp = 32;\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tLOG(Debayer, Error)\n> +\t\t<< \"Unsupported output format \" << outputFormat.toString();\n> +\n> +\treturn -EINVAL;\n> +}\n> +\n> +int DebayerEGL::getShaderVariableLocations(void)\n> +{\n> +\tattributeVertex_ = glGetAttribLocation(programId_, \"vertexIn\");\n> +\tattributeTexture_ = glGetAttribLocation(programId_, \"textureIn\");\n> +\n> +\ttextureUniformBayerDataIn_ = glGetUniformLocation(programId_, \"tex_y\");\n> +\tccmUniformDataIn_ = glGetUniformLocation(programId_, \"ccm\");\n> +\tblackLevelUniformDataIn_ = glGetUniformLocation(programId_, \"blacklevel\");\n> +\tgammaUniformDataIn_ = glGetUniformLocation(programId_, \"gamma\");\n> +\tcontrastUniformDataIn_ = glGetUniformLocation(programId_, \"contrast\");\n> +\n> +\ttextureUniformStep_ = glGetUniformLocation(programId_, \"tex_step\");\n> +\ttextureUniformSize_ = glGetUniformLocation(programId_, \"tex_size\");\n> +\ttextureUniformStrideFactor_ = glGetUniformLocation(programId_, \"stride_factor\");\n> +\ttextureUniformBayerFirstRed_ = glGetUniformLocation(programId_, \"tex_bayer_first_red\");\n> +\ttextureUniformProjMatrix_ = glGetUniformLocation(programId_, \"proj_matrix\");\n> +\n> +\tLOG(Debayer, Debug) << \"vertexIn \" << attributeVertex_ << \" textureIn \" << attributeTexture_\n> +\t\t\t    << \" tex_y \" << textureUniformBayerDataIn_\n> +\t\t\t    << \" ccm \" << ccmUniformDataIn_\n> +\t\t\t    << \" blacklevel \" << blackLevelUniformDataIn_\n> +\t\t\t    << \" gamma \" << gammaUniformDataIn_\n> +\t\t\t    << \" contrast \" << contrastUniformDataIn_\n> +\t\t\t    << \" tex_step \" << textureUniformStep_\n> +\t\t\t    << \" tex_size \" << textureUniformSize_\n> +\t\t\t    << \" stride_factor \" << textureUniformStrideFactor_\n> +\t\t\t    << \" tex_bayer_first_red \" << textureUniformBayerFirstRed_\n> +\t\t\t    << \" proj_matrix \" << textureUniformProjMatrix_;\n> +\treturn 0;\n> +}\n> +\n> +int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputFormat)\n> +{\n> +\tstd::vector<std::string> shaderEnv;\n> +\tunsigned int fragmentShaderDataLen;\n> +\tconst unsigned char *fragmentShaderData;\n> +\tunsigned int vertexShaderDataLen;\n> +\tconst unsigned char *vertexShaderData;\n> +\tGLenum err;\n> +\n> +\t// Target gles 100 glsl requires \"#version x\" as first directive in shader\n\n/* ... */ -- here and elsewhere (including \"Add a eGL base helper class\"\npatch)\n\n> +\tegl_.pushEnv(shaderEnv, \"#version 100\");\n> +\n> +\t// Specify GL_OES_EGL_image_external\n> +\tegl_.pushEnv(shaderEnv, \"#extension GL_OES_EGL_image_external: enable\");\n> +\n> +\t// Tell shaders how to re-order output taking account of how the\n> +\t// pixels are actually stored by GBM\n> +\tswitch (outputFormat) {\n> +\tcase formats::ARGB8888:\n> +\tcase formats::XRGB8888:\n> +\t\tbreak;\n> +\tcase formats::ABGR8888:\n> +\tcase formats::XBGR8888:\n> +\t\tegl_.pushEnv(shaderEnv, \"#define SWAP_BLUE\");\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tgoto invalid_fmt;\n> +\t}\n> +\n> +\t// Pixel location parameters\n> +\tglFormat_ = GL_LUMINANCE;\n> +\tbytesPerPixel_ = 1;\n> +\tshaderStridePixels_ = inputConfig_.stride;\n> +\n> +\tswitch (inputFormat) {\n> +\tcase libcamera::formats::SBGGR8:\n> +\tcase libcamera::formats::SBGGR10_CSI2P:\n> +\tcase libcamera::formats::SBGGR12_CSI2P:\n> +\t\tfirstRed_x_ = 1.0;\n> +\t\tfirstRed_y_ = 1.0;\n> +\t\tbreak;\n> +\tcase libcamera::formats::SGBRG8:\n> +\tcase libcamera::formats::SGBRG10_CSI2P:\n> +\tcase libcamera::formats::SGBRG12_CSI2P:\n> +\t\tfirstRed_x_ = 0.0;\n> +\t\tfirstRed_y_ = 1.0;\n> +\t\tbreak;\n> +\tcase libcamera::formats::SGRBG8:\n> +\tcase libcamera::formats::SGRBG10_CSI2P:\n> +\tcase libcamera::formats::SGRBG12_CSI2P:\n> +\t\tfirstRed_x_ = 1.0;\n> +\t\tfirstRed_y_ = 0.0;\n> +\t\tbreak;\n> +\tcase libcamera::formats::SRGGB8:\n> +\tcase libcamera::formats::SRGGB10_CSI2P:\n> +\tcase libcamera::formats::SRGGB12_CSI2P:\n> +\t\tfirstRed_x_ = 0.0;\n> +\t\tfirstRed_y_ = 0.0;\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tgoto invalid_fmt;\n> +\t\tbreak;\n> +\t};\n> +\n> +\t// Shader selection\n> +\tswitch (inputFormat) {\n> +\tcase libcamera::formats::SBGGR8:\n> +\tcase libcamera::formats::SGBRG8:\n> +\tcase libcamera::formats::SGRBG8:\n> +\tcase libcamera::formats::SRGGB8:\n> +\t\tfragmentShaderData = bayer_unpacked_frag;\n> +\t\tfragmentShaderDataLen = bayer_unpacked_frag_len;\n> +\t\tvertexShaderData = bayer_unpacked_vert;\n> +\t\tvertexShaderDataLen = bayer_unpacked_vert_len;\n> +\t\tbreak;\n> +\tcase libcamera::formats::SBGGR10_CSI2P:\n> +\tcase libcamera::formats::SGBRG10_CSI2P:\n> +\tcase libcamera::formats::SGRBG10_CSI2P:\n> +\tcase libcamera::formats::SRGGB10_CSI2P:\n> +\t\tegl_.pushEnv(shaderEnv, \"#define RAW10P\");\n> +\t\tif (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) {\n> +\t\t\tfragmentShaderData = bayer_unpacked_frag;\n> +\t\t\tfragmentShaderDataLen = bayer_unpacked_frag_len;\n> +\t\t\tvertexShaderData = bayer_unpacked_vert;\n> +\t\t\tvertexShaderDataLen = bayer_unpacked_vert_len;\n> +\t\t\tglFormat_ = GL_RG;\n> +\t\t\tbytesPerPixel_ = 2;\n> +\t\t} else {\n> +\t\t\tfragmentShaderData = bayer_1x_packed_frag;\n> +\t\t\tfragmentShaderDataLen = bayer_1x_packed_frag_len;\n> +\t\t\tvertexShaderData = identity_vert;\n> +\t\t\tvertexShaderDataLen = identity_vert_len;\n> +\t\t\tshaderStridePixels_ = width_;\n> +\t\t}\n> +\t\tbreak;\n> +\tcase libcamera::formats::SBGGR12_CSI2P:\n> +\tcase libcamera::formats::SGBRG12_CSI2P:\n> +\tcase libcamera::formats::SGRBG12_CSI2P:\n> +\tcase libcamera::formats::SRGGB12_CSI2P:\n> +\t\tegl_.pushEnv(shaderEnv, \"#define RAW12P\");\n> +\t\tif (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) {\n> +\t\t\tfragmentShaderData = bayer_unpacked_frag;\n> +\t\t\tfragmentShaderDataLen = bayer_unpacked_frag_len;\n> +\t\t\tvertexShaderData = bayer_unpacked_vert;\n> +\t\t\tvertexShaderDataLen = bayer_unpacked_vert_len;\n> +\t\t\tglFormat_ = GL_RG;\n> +\t\t\tbytesPerPixel_ = 2;\n> +\t\t} else {\n> +\t\t\tfragmentShaderData = bayer_1x_packed_frag;\n> +\t\t\tfragmentShaderDataLen = bayer_1x_packed_frag_len;\n> +\t\t\tvertexShaderData = identity_vert;\n> +\t\t\tvertexShaderDataLen = identity_vert_len;\n> +\t\t\tshaderStridePixels_ = width_;\n> +\t\t}\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tgoto invalid_fmt;\n> +\t\tbreak;\n> +\t};\n> +\n> +\tif (egl_.compileVertexShader(vertexShaderId_, vertexShaderData, vertexShaderDataLen, shaderEnv))\n> +\t\tgoto compile_fail;\n> +\n> +\tif (egl_.compileFragmentShader(fragmentShaderId_, fragmentShaderData, fragmentShaderDataLen, shaderEnv))\n> +\t\tgoto compile_fail;\n> +\n> +\tif (egl_.linkProgram(programId_, vertexShaderId_, fragmentShaderId_))\n> +\t\tgoto link_fail;\n> +\n> +\tegl_.dumpShaderSource(vertexShaderId_);\n> +\tegl_.dumpShaderSource(fragmentShaderId_);\n> +\n> +\t/* Ensure we set the programId_ */\n> +\tegl_.useProgram(programId_);\n> +\terr = glGetError();\n> +\tif (err != GL_NO_ERROR)\n> +\t\tgoto program_fail;\n> +\n> +\tif (getShaderVariableLocations())\n> +\t\tgoto parameters_fail;\n> +\n> +\treturn 0;\n> +\n> +parameters_fail:\n> +\tLOG(Debayer, Error) << \"Program parameters fail\";\n> +\treturn -ENODEV;\n> +\n> +program_fail:\n> +\tLOG(Debayer, Error) << \"Use program error \" << err;\n> +\treturn -ENODEV;\n> +\n> +link_fail:\n> +\tLOG(Debayer, Error) << \"Linking program fail\";\n> +\treturn -ENODEV;\n> +\n> +compile_fail:\n> +\tLOG(Debayer, Error) << \"Compile debayer shaders fail\";\n> +\treturn -ENODEV;\n> +\n> +invalid_fmt:\n> +\tLOG(Debayer, Error) << \"Unsupported input output format combination\";\n> +\treturn -EINVAL;\n> +}\n> +\n> +\n\nThere is an extra blank line here.\n\n> +/**\n> + * \\brief Get the output frame size.\n> + *\n> + * \\return The output frame size.\n> + */\n> +unsigned int DebayerEGL::frameSize()\n> +{\n> +\treturn outputConfig_.frameSize;\n> +}\n> +\n> +int DebayerEGL::configure(const StreamConfiguration &inputCfg,\n> +\t\t\t  const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs,\n> +\t\t\t  bool ccmEnabled)\n> +{\n> +\tif (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0)\n> +\t\treturn -EINVAL;\n> +\n> +\tif (stats_->configure(inputCfg) != 0)\n> +\t\treturn -EINVAL;\n> +\n> +\tif (!ccmEnabled)\n> +\t\treturn -EINVAL;\n> +\n> +\tconst Size &stats_pattern_size = stats_->patternSize();\n> +\tif (inputConfig_.patternSize.width != stats_pattern_size.width ||\n> +\t    inputConfig_.patternSize.height != stats_pattern_size.height) {\n> +\t\tLOG(Debayer, Error)\n> +\t\t\t<< \"mismatching stats and debayer pattern sizes for \"\n> +\t\t\t<< inputCfg.pixelFormat.toString();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tinputConfig_.stride = inputCfg.stride;\n> +\tinputPixelFormat_ = inputCfg.pixelFormat;\n> +\twidth_ = inputCfg.size.width;\n> +\theight_ = inputCfg.size.height;\n> +\n> +\n\nAnd here.\n\n> +\tif (outputCfgs.size() != 1) {\n> +\t\tLOG(Debayer, Error)\n> +\t\t\t<< \"Unsupported number of output streams: \"\n> +\t\t\t<< outputCfgs.size();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tStreamConfiguration &outputCfg = outputCfgs[0];\n> +\tSizeRange outSizeRange = sizes(inputCfg.pixelFormat, inputCfg.size);\n> +\tstd::tie(outputConfig_.stride, outputConfig_.frameSize) =\n> +\t\tstrideAndFrameSize(outputCfg.pixelFormat, outputCfg.size);\n> +\n> +\tif (!outSizeRange.contains(outputCfg.size) || outputConfig_.stride != outputCfg.stride) {\n> +\t\tLOG(Debayer, Error)\n> +\t\t\t<< \"Invalid output size/stride: \"\n> +\t\t\t<< \"\\n  \" << outputCfg.size << \" (\" << outSizeRange << \")\"\n> +\t\t\t<< \"\\n  \" << outputCfg.stride << \" (\" << outputConfig_.stride << \")\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\toutputPixelFormat_ = outputCfg.pixelFormat;\n> +\toutputSize_ = outputCfg.size;\n> +\n> +\twindow_.x = ((inputCfg.size.width - outputCfg.size.width) / 2) &\n> +\t\t    ~(inputConfig_.patternSize.width - 1);\n> +\twindow_.y = ((inputCfg.size.height - outputCfg.size.height) / 2) &\n> +\t\t    ~(inputConfig_.patternSize.height - 1);\n> +\twindow_.width = outputCfg.size.width;\n> +\twindow_.height = outputCfg.size.height;\n> +\n> +\t/*\n> +\t * Don't pass x,y from window_ since process() already adjusts for it.\n> +\t * But crop the window to 2/3 of its width and height for speedup.\n> +\t */\n> +\tstats_->setWindow(Rectangle(window_.size()));\n> +\n> +\treturn 0;\n> +}\n> +\n> +Size DebayerEGL::patternSize(PixelFormat inputFormat)\n> +{\n> +\tDebayerEGL::DebayerInputConfig config;\n> +\n> +\tif (getInputConfig(inputFormat, config) != 0)\n> +\t\treturn {};\n> +\n> +\treturn config.patternSize;\n> +}\n> +\n> +std::vector<PixelFormat> DebayerEGL::formats(PixelFormat inputFormat)\n> +{\n> +\tDebayerEGL::DebayerInputConfig config;\n> +\n> +\tif (getInputConfig(inputFormat, config) != 0)\n> +\t\treturn std::vector<PixelFormat>();\n> +\n> +\treturn config.outputFormats;\n> +}\n> +\n> +std::tuple<unsigned int, unsigned int>\n> +DebayerEGL::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size)\n> +{\n> +\tDebayerEGL::DebayerOutputConfig config;\n> +\n> +\tif (getOutputConfig(outputFormat, config) != 0)\n> +\t\treturn std::make_tuple(0, 0);\n> +\n> +\t/* Align stride to 256 bytes as a generic GPU memory access alignment */\n> +\tunsigned int stride = libcamera::utils::alignUp(size.width * config.bpp / 8, 256);\n> +\n> +\treturn std::make_tuple(stride, stride * size.height);\n> +}\n> +\n> +void DebayerEGL::setShaderVariableValues(DebayerParams &params)\n> +{\n> +\t/*\n> +\t * Raw Bayer 8-bit, and packed raw Bayer 10-bit/12-bit formats\n> +\t * are stored in a GL_LUMINANCE texture. The texture width is\n> +\t * equal to the stride.\n> +\t */\n> +\tGLfloat firstRed[] = { firstRed_x_, firstRed_y_ };\n> +\tGLfloat imgSize[] = { (GLfloat)width_,\n> +\t\t\t      (GLfloat)height_ };\n> +\tGLfloat Step[] = { static_cast<float>(bytesPerPixel_) / (inputConfig_.stride - 1),\n> +\t\t\t   1.0f / (height_ - 1) };\n> +\tGLfloat Stride = (GLfloat)width_ / (shaderStridePixels_ / bytesPerPixel_);\n> +\tGLfloat scaleX = (GLfloat)window_.width / width_;\n> +\tGLfloat scaleY = (GLfloat)window_.height / height_;\n> +\tGLfloat transX = -(1.0f - scaleX);\n> +\tGLfloat transY = -(1.0f - scaleY);\n> +\tGLfloat scale = std::max(scaleX, scaleY);\n> +\tGLfloat projMatrix[] = {\n> +\t\tscale, 0, 0, 0,\n> +\t\t0, scale, 0, 0,\n> +\t\t0, 0, 1, 0,\n> +\t\ttransX, transY, 0, 1\n> +\t};\n> +\n> +\t// vertexIn - bayer_8.vert\n> +\tglEnableVertexAttribArray(attributeVertex_);\n> +\tglVertexAttribPointer(attributeVertex_, 2, GL_FLOAT, GL_TRUE,\n> +\t\t\t      2 * sizeof(GLfloat), vcoordinates);\n> +\n> +\t// textureIn - bayer_8.vert\n> +\tglEnableVertexAttribArray(attributeTexture_);\n> +\tglVertexAttribPointer(attributeTexture_, 2, GL_FLOAT, GL_TRUE,\n> +\t\t\t      2 * sizeof(GLfloat), tcoordinates);\n> +\n> +\t// Set the sampler2D to the respective texture unit for each texutre\n> +\t// To simultaneously sample multiple textures we need to use multiple\n> +\t// texture units\n> +\tglUniform1i(textureUniformBayerDataIn_, eglImageBayerIn_->texture_unit_uniform_id_);\n> +\n> +\t// These values are:\n> +\t// firstRed = tex_bayer_first_red - bayer_8.vert\n> +\t// imgSize = tex_size - bayer_8.vert\n> +\t// step = tex_step - bayer_8.vert\n> +\t// Stride = stride_factor identity.vert\n> +\t// textureUniformProjMatri = No scaling\n> +\tglUniform2fv(textureUniformBayerFirstRed_, 1, firstRed);\n> +\tglUniform2fv(textureUniformSize_, 1, imgSize);\n> +\tglUniform2fv(textureUniformStep_, 1, Step);\n> +\tglUniform1f(textureUniformStrideFactor_, Stride);\n> +\tglUniformMatrix4fv(textureUniformProjMatrix_, 1, GL_FALSE, projMatrix);\n> +\n> +\tLOG(Debayer, Debug) << \"vertexIn \" << attributeVertex_ << \" textureIn \" << attributeTexture_\n> +\t\t\t    << \" tex_y \" << textureUniformBayerDataIn_\n> +\t\t\t    << \" tex_step \" << textureUniformStep_\n> +\t\t\t    << \" tex_size \" << textureUniformSize_\n> +\t\t\t    << \" stride_factor \" << textureUniformStrideFactor_\n> +\t\t\t    << \" tex_bayer_first_red \" << textureUniformBayerFirstRed_;\n> +\n> +\tLOG(Debayer, Debug) << \"textureUniformY_ = 0 \"\n> +\t\t\t    << \" firstRed.x \" << firstRed[0]\n> +\t\t\t    << \" firstRed.y \" << firstRed[1]\n> +\t\t\t    << \" textureUniformSize_.width \" << imgSize[0]\n> +\t\t\t    << \" textureUniformSize_.height \" << imgSize[1]\n> +\t\t\t    << \" textureUniformStep_.x \" << Step[0]\n> +\t\t\t    << \" textureUniformStep_.y \" << Step[1]\n> +\t\t\t    << \" textureUniformStrideFactor_ \" << Stride\n> +\t\t\t    << \" textureUniformProjMatrix_ \" << textureUniformProjMatrix_;\n> +\n> +\tGLfloat ccm[9] = {\n> +\t\tparams.ccm[0][0],\n> +\t\tparams.ccm[0][1],\n> +\t\tparams.ccm[0][2],\n> +\t\tparams.ccm[1][0],\n> +\t\tparams.ccm[1][1],\n> +\t\tparams.ccm[1][2],\n> +\t\tparams.ccm[2][0],\n> +\t\tparams.ccm[2][1],\n> +\t\tparams.ccm[2][2],\n> +\t};\n> +\tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);\n> +\tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.ccm;\n> +\n> +\t/*\n> +\t * 0 = Red, 1 = Green, 2 = Blue\n> +\t */\n> +\tglUniform3f(blackLevelUniformDataIn_, params.blackLevel[0], params.blackLevel[1], params.blackLevel[2]);\n> +\tLOG(Debayer, Debug) << \" blackLevelUniformDataIn_ \" << blackLevelUniformDataIn_ << \" data \" << params.blackLevel;\n> +\n> +\t/*\n> +\t * Gamma\n> +\t */\n> +\tglUniform1f(gammaUniformDataIn_, params.gamma);\n> +\tLOG(Debayer, Debug) << \" gammaUniformDataIn_ \" << gammaUniformDataIn_ << \" data \" << params.gamma;\n> +\n> +\t/*\n> +\t * Contrast\n> +\t */\n> +\tglUniform1f(contrastUniformDataIn_, params.contrast);\n> +\tLOG(Debayer, Debug) << \" contrastUniformDataIn_ \" << contrastUniformDataIn_ << \" data \" << params.contrast;\n> +\n> +\treturn;\n> +}\n> +\n> +int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, DebayerParams &params)\n> +{\n> +\t/* eGL context switch */\n> +\tegl_.makeCurrent();\n> +\n> +\t/* Create a standard texture input */\n> +\tegl_.createTexture2D(eglImageBayerIn_, glFormat_, inputConfig_.stride / bytesPerPixel_, height_, in.planes()[0].data());\n> +\n> +\t/* Generate the output render framebuffer as render to texture */\n> +\tegl_.createOutputDMABufTexture2D(eglImageBayerOut_, out_fd);\n> +\n> +\tsetShaderVariableValues(params);\n> +\tglViewport(0, 0, width_, height_);\n> +\tglClear(GL_COLOR_BUFFER_BIT);\n> +\tglDrawArrays(GL_TRIANGLE_FAN, 0, DEBAYER_OPENGL_COORDS);\n> +\n> +\tGLenum err = glGetError();\n> +\tif (err != GL_NO_ERROR) {\n> +\t\tLOG(eGL, Error) << \"Drawing scene fail \" << err;\n> +\t\treturn -ENODEV;\n> +\t} else {\n> +\t\tegl_.syncOutput();\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, DebayerParams params)\n> +{\n> +\tbench_.startFrame();\n> +\n> +\tstd::vector<DmaSyncer> dmaSyncers;\n> +\n> +\tdmaSyncBegin(dmaSyncers, input, nullptr);\n> +\n> +\tsetParams(params);\n> +\n> +\t/* Copy metadata from the input buffer */\n> +\tFrameMetadata &metadata = output->_d()->metadata();\n> +\tmetadata.status = input->metadata().status;\n> +\tmetadata.sequence = input->metadata().sequence;\n> +\tmetadata.timestamp = input->metadata().timestamp;\n> +\n> +\tMappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read);\n> +\tif (!in.isValid()) {\n> +\t\tLOG(Debayer, Error) << \"mmap-ing buffer(s) failed\";\n> +\t\tgoto error;\n> +\t}\n> +\n> +\tif (debayerGPU(in, output->planes()[0].fd.get(), params)) {\n> +\t\tLOG(Debayer, Error) << \"debayerGPU failed\";\n> +\t\tgoto error;\n> +\t}\n> +\n> +\tbench_.finishFrame();\n> +\n> +\tmetadata.planes()[0].bytesused = output->planes()[0].length;\n> +\n> +\t/* Calculate stats for the whole frame */\n> +\tstats_->processFrame(frame, 0, input);\n> +\tdmaSyncers.clear();\n> +\n> +\toutputBufferReady.emit(output);\n> +\tinputBufferReady.emit(input);\n> +\n> +\treturn;\n> +\n> +error:\n> +\tbench_.finishFrame();\n> +\tmetadata.status = FrameMetadata::FrameError;\n> +\treturn;\n> +}\n> +\n> +int DebayerEGL::start()\n> +{\n> +\tGLint maxTextureImageUnits;\n> +\n> +\tif (gbmSurface_.createDevice())\n> +\t\treturn -ENODEV;\n> +\n> +\tif (egl_.initEGLContext(&gbmSurface_))\n> +\t\treturn -ENODEV;\n> +\n> +\tglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits);\n> +\n> +\tLOG(Debayer, Debug) << \"Available fragment shader texture units \" << maxTextureImageUnits;\n> +\n> +\t// Raw bayer input as texture\n> +\teglImageBayerIn_ = std::make_unique<eGLImage>(width_, height_, 32, inputConfig_.stride, GL_TEXTURE0, 0);\n> +\n> +\t// Texture we will render to\n> +\teglImageBayerOut_ = std::make_unique<eGLImage>(outputSize_.width, outputSize_.height, 31, outputConfig_.stride, GL_TEXTURE1, 1);\n> +\n> +\tif (initBayerShaders(inputPixelFormat_, outputPixelFormat_))\n> +\t\treturn -EINVAL;\n> +\n> +\treturn 0;\n> +}\n> +\n> +void DebayerEGL::stop()\n> +{\n> +\teglImageBayerOut_.release();\n> +\teglImageBayerIn_.release();\n> +\n> +\tegl_.cleanUp();\n> +}\n> +\n> +SizeRange DebayerEGL::sizes(PixelFormat inputFormat, const Size &inputSize)\n> +{\n> +\tSize patternSize = this->patternSize(inputFormat);\n> +\tunsigned int borderHeight = patternSize.height;\n> +\n> +\tif (patternSize.isNull())\n> +\t\treturn {};\n> +\n> +\t/* No need for top/bottom border with a pattern height of 2 */\n> +\tif (patternSize.height == 2)\n> +\t\tborderHeight = 0;\n> +\n> +\t/*\n> +\t * For debayer interpolation a border is kept around the entire image\n> +\t * and the minimum output size is pattern-height x pattern-width.\n> +\t */\n> +\tif (inputSize.width < (3 * patternSize.width) ||\n> +\t    inputSize.height < (2 * borderHeight + patternSize.height)) {\n> +\t\tLOG(Debayer, Warning)\n> +\t\t\t<< \"Input format size too small: \" << inputSize.toString();\n> +\t\treturn {};\n> +\t}\n> +\n> +\treturn SizeRange(Size(patternSize.width, patternSize.height),\n> +\t\t\t Size((inputSize.width - 2 * patternSize.width) & ~(patternSize.width - 1),\n> +\t\t\t      (inputSize.height - 2 * borderHeight) & ~(patternSize.height - 1)),\n> +\t\t\t patternSize.width, patternSize.height);\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h\n> new file mode 100644\n> index 000000000..1bbae5234\n> --- /dev/null\n> +++ b/src/libcamera/software_isp/debayer_egl.h\n> @@ -0,0 +1,142 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2025, Bryan O'Donoghue.\n> + *\n> + * Authors:\n> + * Bryan O'Donoghue <bryan.odonoghue@linaro.org>\n> + *\n> + * debayer_opengl.h - EGL debayer header\n\nNo file name.\n\n> + */\n> +\n> +#pragma once\n> +\n> +#include <memory>\n> +#include <stdint.h>\n> +#include <vector>\n> +\n> +#define GL_GLEXT_PROTOTYPES\n> +#define EGL_EGLEXT_PROTOTYPES\n> +#include <libcamera/base/object.h>\n> +\n> +#include \"libcamera/internal/bayer_format.h\"\n> +#include \"libcamera/internal/egl.h\"\n> +#include \"libcamera/internal/framebuffer.h\"\n> +#include \"libcamera/internal/mapped_framebuffer.h\"\n> +#include \"libcamera/internal/software_isp/benchmark.h\"\n> +#include \"libcamera/internal/software_isp/swstats_cpu.h\"\n> +\n> +#include <EGL/egl.h>\n> +#include <EGL/eglext.h>\n> +#include <GLES3/gl32.h>\n> +\n> +#include \"debayer.h\"\n> +\n> +namespace libcamera {\n> +\n> +#define DEBAYER_EGL_MIN_SIMPLE_RGB_GAIN_TEXTURE_UNITS 4\n> +#define DEBAYER_OPENGL_COORDS 4\n> +\n> +class DebayerEGL : public Debayer\n> +{\n> +public:\n> +\tDebayerEGL(std::unique_ptr<SwStatsCpu> stats, const GlobalConfiguration &configuration);\n> +\t~DebayerEGL();\n> +\n> +\tint configure(const StreamConfiguration &inputCfg,\n> +\t\t      const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs,\n> +\t\t      bool ccmEnabled);\n> +\n> +\tSize patternSize(PixelFormat inputFormat);\n> +\n> +\tstd::vector<PixelFormat> formats(PixelFormat input);\n> +\tstd::tuple<unsigned int, unsigned int> strideAndFrameSize(const PixelFormat &outputFormat, const Size &size);\n> +\n> +\tvoid process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, DebayerParams params);\n> +\tint start();\n> +\tvoid stop();\n> +\n> +\tconst SharedFD &getStatsFD() { return stats_->getStatsFD(); }\n> +\tunsigned int frameSize();\n> +\n> +\tSizeRange sizes(PixelFormat inputFormat, const Size &inputSize);\n> +\n> +private:\n> +\tstatic int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config);\n> +\tstatic int getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config);\n> +\tint setupStandardBayerOrder(BayerFormat::Order order);\n> +\tvoid pushEnv(std::vector<std::string> &shaderEnv, const char *str);\n> +\tint initBayerShaders(PixelFormat inputFormat, PixelFormat outputFormat);\n> +\tint initEGLContext();\n> +\tint generateTextures();\n> +\tint compileShaderProgram(GLuint &shaderId, GLenum shaderType,\n> +\t\t\t\t unsigned char *shaderData, int shaderDataLen,\n> +\t\t\t\t std::vector<std::string> shaderEnv);\n> +\tint linkShaderProgram(void);\n> +\tint getShaderVariableLocations();\n> +\tvoid setShaderVariableValues(DebayerParams &params);\n> +\tvoid configureTexture(GLuint &texture);\n> +\tint debayerGPU(MappedFrameBuffer &in, int out_fd, DebayerParams &params);\n> +\n> +\t// Shader program identifiers\n> +\tGLuint vertexShaderId_;\n> +\tGLuint fragmentShaderId_;\n> +\tGLuint programId_;\n> +\tenum {\n> +\t\tBAYER_INPUT_INDEX = 0,\n> +\t\tBAYER_OUTPUT_INDEX,\n> +\t\tBAYER_BUF_NUM,\n> +\t};\n> +\n> +\t// Pointer to object representing input texture\n> +\tstd::unique_ptr<eGLImage> eglImageBayerIn_;\n> +\tstd::unique_ptr<eGLImage> eglImageBayerOut_;\n> +\n> +\t// Shader parameters\n> +\tfloat firstRed_x_;\n> +\tfloat firstRed_y_;\n> +\tGLint attributeVertex_;\n> +\tGLint attributeTexture_;\n> +\tGLint textureUniformStep_;\n> +\tGLint textureUniformSize_;\n> +\tGLint textureUniformStrideFactor_;\n> +\tGLint textureUniformBayerFirstRed_;\n> +\tGLint textureUniformProjMatrix_;\n> +\n> +\tGLint textureUniformBayerDataIn_;\n> +\n> +\t// Represent per-frame CCM as a uniform vector of floats 3 x 3\n> +\tGLint ccmUniformDataIn_;\n> +\n> +\t// Black Level compensation\n> +\tGLint blackLevelUniformDataIn_;\n> +\n> +\t// Gamma\n> +\tGLint gammaUniformDataIn_;\n> +\n> +\t// Contrast\n> +\tGLint contrastUniformDataIn_;\n> +\n> +\tRectangle window_;\n> +\tstd::unique_ptr<SwStatsCpu> stats_;\n> +\teGL egl_;\n> +\tGBM gbmSurface_;\n> +\tuint32_t width_;\n> +\tuint32_t height_;\n> +\tGLint glFormat_;\n> +\tunsigned int bytesPerPixel_;\n> +\tuint32_t shaderStridePixels_;\n> +\tGLfloat vcoordinates[DEBAYER_OPENGL_COORDS][2] = {\n> +\t\t{ -1.0f, -1.0f },\n> +\t\t{ -1.0f, +1.0f },\n> +\t\t{ +1.0f, +1.0f },\n> +\t\t{ +1.0f, -1.0f },\n> +\t};\n> +\tGLfloat tcoordinates[DEBAYER_OPENGL_COORDS][2] = {\n> +\t\t{ 0.0f, 0.0f },\n> +\t\t{ 0.0f, 1.0f },\n> +\t\t{ 1.0f, 1.0f },\n> +\t\t{ 1.0f, 0.0f },\n> +\t};\n> +};\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build\n> index 59fa5f02a..c61ac7d59 100644\n> --- a/src/libcamera/software_isp/meson.build\n> +++ b/src/libcamera/software_isp/meson.build\n> @@ -2,6 +2,7 @@\n>  \n>  softisp_enabled = pipelines.contains('simple')\n>  summary({'SoftISP support' : softisp_enabled}, section : 'Configuration')\n> +summary({'SoftISP GPU acceleration' : gles_headless_enabled}, section : 'Configuration')\n>  \n>  if not softisp_enabled\n>      subdir_done()\n> @@ -14,3 +15,10 @@ libcamera_internal_sources += files([\n>      'software_isp.cpp',\n>      'swstats_cpu.cpp',\n>  ])\n> +\n> +if softisp_enabled and gles_headless_enabled\n> +    config_h.set('HAVE_DEBAYER_EGL', 1)\n> +    libcamera_internal_sources += files([\n> +        'debayer_egl.cpp',\n> +    ])\n> +endif","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 25495C3257\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 15 Dec 2025 20:15:25 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 34066619F2;\n\tMon, 15 Dec 2025 21:15:24 +0100 (CET)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.129.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4A3B7615B2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 15 Dec 2025 21:15:22 +0100 (CET)","from mail-wr1-f70.google.com (mail-wr1-f70.google.com\n\t[209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-57-93aEh3SsOJiTi_mHtHl0XA-1; Mon, 15 Dec 2025 15:15:19 -0500","by mail-wr1-f70.google.com with SMTP id\n\tffacd0b85a97d-43102ac1da8so527576f8f.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 15 Dec 2025 12:15:19 -0800 (PST)","from mzamazal-thinkpadp1gen7.tpbc.csb\n\t(ip-77-48-47-2.net.vodafone.cz. [77.48.47.2])\n\tby smtp.gmail.com with ESMTPSA id\n\t5b1f17b1804b1-47a8f6e5baasm217500795e9.13.2025.12.15.12.15.16\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 15 Dec 2025 12:15:16 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"UkPpYeeA\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1765829721;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=2058FTBONa47dI+FvoGR5ka6NKVbhBTLdbgnGHKicMU=;\n\tb=UkPpYeeARVFjy8/F8zi2+aFI0obdIYklX+KOO56c0IvlRavnxEHcFsiKO4ZbL1lbEUbk6V\n\tl3zLx7wUdykD5dTJnnbgbsDAZD1VzI92Nf+NESTqi5WW/VdGXr+QSHVk2nI6yjM9mRDgSt\n\tSaCyqPYY+JkDWaxN62Qm7Mn/bMbyzDw=","X-MC-Unique":"93aEh3SsOJiTi_mHtHl0XA-1","X-Mimecast-MFC-AGG-ID":"93aEh3SsOJiTi_mHtHl0XA_1765829718","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1765829718; x=1766434518;\n\th=mime-version:user-agent:message-id:date:references:in-reply-to\n\t:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject\n\t:date:message-id:reply-to;\n\tbh=2058FTBONa47dI+FvoGR5ka6NKVbhBTLdbgnGHKicMU=;\n\tb=SM5a0OYpnl605mYdUEVn2jHD6P7j6Z+v1T8J4nz9TqnRcEOZAZ/8ZOIkKb8DcdJDMc\n\to/c0lq9Shr2Sl0rOOUpEhymQu8oreZBX44HHXUQAsoVx8iwmALyTCbObvMn0QgxDWACk\n\tU+ODBeGnzkYvqu8MXO1CDFAjq2YURi0s53oF0lXcoVTA63R/hQjVyaHdscPwzZvaUkqb\n\tsgRpusxuEU8GMjsCN5E9iAU308ujeCZeLfEB6O0gumE79tzlu+BD1i5iMkXk94zA++WD\n\tECrvToUOA4K71lg9eFuh2sZh0tnsmAIFEd+KTdZG1ITUKu9ixqS/txn+HzPjry7PGTlo\n\tUALg==","X-Gm-Message-State":"AOJu0YxWv1RkaKaXjVIiSb5DOBfis9UsfUw5IIRLGDQ0Q+8Y+XWaiues\n\toc+igY61Et+6pKWvbOtxl+GXPAIUeDX1nozBrlXKy0r0e6KLkULlQQI/+ByWN1fCbFjGczqqTbw\n\tK+gdDV1QUfrqdktjdjfB3wZPKEKg0CYvkMcl8O4hIMkUprh2++2bLshnOTREuqrqDoQwtL9ySV2\n\tQ=","X-Gm-Gg":"AY/fxX56K7o0JzPuvWTUqyKB++tlb5k4JOEesuUMf17Wik37+1O+f2ZjslNE/SFy5Zk\n\tmVCxC+89OIAZL7YuJj4qdiSibBrA7+zFxewXCYp32nwLCap9zhJ5P4cLPDd3/pgX5H+wmCg3fTO\n\tuICuuN6HHWhFF69bFaInBM/Y3iERnJNea5ZDjEqcTSnbudhiQMoF7EY/3EBoDqvb25nosnY9lnY\n\taS4f11xUIuCqq76BPWaM34SniuX7K6D5BxOr232wwZVZO0xoX4iuzm1U9I0TuLmaNxrcuszhEFY\n\tSsSdg1nxFJjp1Yfdk5VDqkbxdLuZJI/xaho3zE6gkHL/QgTqxKtPqgH4ekNok0kTgPfvHyr2s09\n\tfUTUCQmphbBmujHeiT5/MvIRYwbcNeYrslltWoG8JbAEj4H51m22Qw6w9o+zWj9Y=","X-Received":["by 2002:a05:600c:8119:b0:477:98f7:2aec with SMTP id\n\t5b1f17b1804b1-47a8f8a7170mr119777445e9.3.1765829718178; \n\tMon, 15 Dec 2025 12:15:18 -0800 (PST)","by 2002:a05:600c:8119:b0:477:98f7:2aec with SMTP id\n\t5b1f17b1804b1-47a8f8a7170mr119777235e9.3.1765829717535; \n\tMon, 15 Dec 2025 12:15:17 -0800 (PST)"],"X-Google-Smtp-Source":"AGHT+IFFGrXLWNEOLTXWybuAkeF9v28ggV/P4HFaeC4xr68p8ixPgzGkd1+3xAS9sW2U+ZbJs4LtWw==","From":"Milan Zamazal <mzamazal@redhat.com>","To":"Bryan O'Donoghue <bryan.odonoghue@linaro.org>","Cc":"libcamera-devel@lists.libcamera.org,  pavel@ucw.cz,  Robert Mader\n\t<robert.mader@collabora.com>","Subject":"Re: [PATCH v8 14/26] libcamera: software_isp: debayer_egl: Add an\n\teGL Debayer class","In-Reply-To":"<20251212002937.3118-15-bryan.odonoghue@linaro.org> (Bryan\n\tO'Donoghue's message of \"Fri, 12 Dec 2025 00:29:25 +0000\")","References":"<20251212002937.3118-1-bryan.odonoghue@linaro.org>\n\t<20251212002937.3118-15-bryan.odonoghue@linaro.org>","Date":"Mon, 15 Dec 2025 21:15:16 +0100","Message-ID":"<851pkvcxij.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","User-Agent":"Gnus/5.13 (Gnus v5.13)","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"f38IQvHhYNGd5JtEITCUlcAqzlXsM-EK5Dze-7RP_tQ_1765829718","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":37417,"web_url":"https://patchwork.libcamera.org/comment/37417/","msgid":"<f8d21786-4981-4f53-9068-9a07481cbefb@linaro.org>","date":"2025-12-17T06:40:36","subject":"Re: [PATCH v8 14/26] libcamera: software_isp: debayer_egl: Add an\n\teGL Debayer class","submitter":{"id":175,"url":"https://patchwork.libcamera.org/api/people/175/","name":"Bryan O'Donoghue","email":"bryan.odonoghue@linaro.org"},"content":"On 14/12/2025 13:34, Robert Mader wrote:\n> Hi\n> \n> On 12.12.25 01:29, Bryan O'Donoghue wrote:\n>> ...\n>> +}\n>> +\n>> +void DebayerEGL::setShaderVariableValues(DebayerParams &params)\n>> +{\n>> +    /*\n>> +     * Raw Bayer 8-bit, and packed raw Bayer 10-bit/12-bit formats\n>> +     * are stored in a GL_LUMINANCE texture. The texture width is\n>> +     * equal to the stride.\n>> +     */\n>> +    GLfloat firstRed[] = { firstRed_x_, firstRed_y_ };\n>> +    GLfloat imgSize[] = { (GLfloat)width_,\n>> +                  (GLfloat)height_ };\n>> +    GLfloat Step[] = { static_cast<float>(bytesPerPixel_) / \n>> (inputConfig_.stride - 1),\n>> +               1.0f / (height_ - 1) };\n>> +    GLfloat Stride = (GLfloat)width_ / (shaderStridePixels_ / \n>> bytesPerPixel_);\n>> +    GLfloat scaleX = (GLfloat)window_.width / width_;\n>> +    GLfloat scaleY = (GLfloat)window_.height / height_;\n>> +    GLfloat transX = -(1.0f - scaleX);\n>> +    GLfloat transY = -(1.0f - scaleY);\n>> +    GLfloat scale = std::max(scaleX, scaleY);\n>> +    GLfloat projMatrix[] = {\n>> +        scale, 0, 0, 0,\n>> +        0, scale, 0, 0,\n>> +        0, 0, 1, 0,\n>> +        transX, transY, 0, 1\n>> +    };\n> \n> I made a small cleanup for this to make it easier to understand - mind \n> cherry-picking / squashing (and adopting as you see fit) https:// \n> gitlab.freedesktop.org/rmader/libcamera/-/ \n> commit/53d61543dfaa5ee0b06e189e701e9319d5c38eca ?\n> \n\npicked\n\n---\nbod","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 7EADCC3257\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 17 Dec 2025 06:40:41 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8706361A32;\n\tWed, 17 Dec 2025 07:40:40 +0100 (CET)","from mail-wm1-x342.google.com (mail-wm1-x342.google.com\n\t[IPv6:2a00:1450:4864:20::342])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 138D5615B2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 17 Dec 2025 07:40:39 +0100 (CET)","by mail-wm1-x342.google.com with SMTP id\n\t5b1f17b1804b1-4775ae5684fso23328935e9.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 16 Dec 2025 22:40:39 -0800 (PST)","from [192.168.0.35] (188-141-3-146.dynamic.upc.ie. [188.141.3.146])\n\tby smtp.gmail.com with ESMTPSA id\n\tffacd0b85a97d-4310ada850dsm3103621f8f.6.2025.12.16.22.40.37\n\t(version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n\tTue, 16 Dec 2025 22:40:38 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=linaro.org header.i=@linaro.org\n\theader.b=\"z3UWLl4c\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=linaro.org; s=google; t=1765953638; x=1766558438;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:in-reply-to:from:content-language\n\t:references:cc:to:subject:user-agent:mime-version:date:message-id\n\t:from:to:cc:subject:date:message-id:reply-to;\n\tbh=knT3o15zlNogg3N4d9CNg1muX7ePEggGPH+J4UMd390=;\n\tb=z3UWLl4cK9FIZAeV0ot4gofj1Hmw46kRn3lU9yZARWrkX99vkGDb4YqbkUKc+14t4i\n\tvT1FOwombTElLXEGiSMiy9mno3uZTy/RXktDlOwf0k8/fatBSbuTR6Q6WME5qV8UcCr2\n\tEGjBTMk51sqoZKOnYJYstvv7ETm+fOM8/TfKFs5gP2SCDU51ZRcxKxtbcXHd7JADNFDc\n\t+ELzqNpGZwj3nhuOFuZwmZuhwFRLph/Ki6TwdY73j/m62mi0fbtSGM2ou5Jrn221+HXZ\n\tznDk6/SHE3E4NC9QuoHUzCYCannyuYsqrMC/zKBsMVtIH3MiiDhtr1sABQu/GhlOtu7h\n\t9d1w==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1765953638; x=1766558438;\n\th=content-transfer-encoding:in-reply-to:from:content-language\n\t:references:cc:to:subject:user-agent:mime-version:date:message-id\n\t:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=knT3o15zlNogg3N4d9CNg1muX7ePEggGPH+J4UMd390=;\n\tb=ZOZeM5+lsDhoMRaYOkqL48KDPf30dtS5OZHn+N1AEIhN84wQturbzLg+X0xCbJV7Dy\n\tkUE/eoofjZmvFppxFDYIrkJYErWeYMQ4gyyG44REmU5XxU7BrWx12WFTSmjlDdEFkEd2\n\taeAq6nR216eHfyNcs0TQ+rH4eubBgOBjUBWsV75XvVnVQzCYRLdLHLvVX8OzbxR6/zQK\n\t5acHYTEO46HWyVfE3hzgbll0CPQSAx8R/f0t5vNvXsh3bppD3VIlX+eeCVYYeh9ePG55\n\tlM/nIyqeWaT9gfqmMu+Pla7g9ycHdQd+h2VLjBI2xcM4xhrB8+vJTj3uMSx7Rkyh2CYP\n\toUHg==","X-Forwarded-Encrypted":"i=1;\n\tAJvYcCWmageai0wUVlrc6Hm6+MCC9X1z5TkalLA2ic5FKGx7/1XjAEQPajQR91rwPwMTJcgxY/PQ1wjFeRvy721iYbs=@lists.libcamera.org","X-Gm-Message-State":"AOJu0Ywo6vsbdk9lHNRsY2iIHbtLfmh7xixa8m+Oa0GcZJuk5KLPoVhb\n\txNwYBJ/WgfzRU8tE4ppvzGzOHygp4BcZrw0bYF1pwFpRlTFRHrYHb8B1NC+PNPFNmOg=","X-Gm-Gg":"AY/fxX4GM+9Qrp7zCLbKy0ee5WFlNVLQiGIzzW//Fslxfj0T8gfpJTnxx9EShF44IGp\n\tDEpcrcrBDLPTZoDv7AKUeOEsqFQDjsN8eJyk1IKzsFUkBrhHsWBQnUpNGfyKGaZBw68PWra514V\n\tOrPAhTAojefuI5L+qOZRIxU9Q9jYbh2FI0gGhPH+58v8eu1WfCxRTOxTrYKlGThvBFY1eYykJZL\n\tErQzES+u8S4Af6FZGnPy9BljMmrPGDCuO6uUIRoFoK4c+8SuzYBXJr79u4CwfPAw5XHhAKpiu1i\n\tJFiv5NOKUzamUW8/uiBtKGCuXnYlrUKZJW/ybELsvKfeD2kGgsyxLAfkC1FiqYKB5+OX64iqvXo\n\t92E2Q301V3u3asUXwhoGdco95fBWH1STmw/Zs6x1ro3RO6PBTO9cBAyZmgvQ2GkD3Q7Mw/w9d16\n\t954HyPpBksWRo8TubW44U1F7vBNsEg8JnDoCSaiR0cLIuuLh2h3boV","X-Google-Smtp-Source":"AGHT+IFc7iPmXmuiYh1UZ2p8LhhZt7bQdJkQw9jNTSmItkD4LPSIw8J3iCXH8ILyi4EvrvdTuF3XIQ==","X-Received":"by 2002:a05:600c:3f10:b0:47a:7fd0:9efc with SMTP id\n\t5b1f17b1804b1-47a8f8cd9cfmr200429725e9.15.1765953638579; \n\tTue, 16 Dec 2025 22:40:38 -0800 (PST)","Message-ID":"<f8d21786-4981-4f53-9068-9a07481cbefb@linaro.org>","Date":"Wed, 17 Dec 2025 06:40:36 +0000","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v8 14/26] libcamera: software_isp: debayer_egl: Add an\n\teGL Debayer class","To":"Robert Mader <robert.mader@collabora.com>,\n\tlibcamera-devel@lists.libcamera.org","Cc":"pavel@ucw.cz, Milan Zamazal <mzamazal@redhat.com>","References":"<20251212002937.3118-1-bryan.odonoghue@linaro.org>\n\t<20251212002937.3118-15-bryan.odonoghue@linaro.org>\n\t<d3978548-f0b5-439f-82b8-51e824682666@collabora.com>","Content-Language":"en-US","From":"Bryan O'Donoghue <bryan.odonoghue@linaro.org>","In-Reply-To":"<d3978548-f0b5-439f-82b8-51e824682666@collabora.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]