[{"id":39759,"web_url":"https://patchwork.libcamera.org/comment/39759/","msgid":"<73ffa103-4246-4fb2-9fce-cf18e863999c@nxsw.ie>","date":"2026-07-20T10:56:21","subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add LSC\n\tsupport","submitter":{"id":226,"url":"https://patchwork.libcamera.org/api/people/226/","name":"Bryan O'Donoghue","email":"bod.linux@nxsw.ie"},"content":"On 16/07/2026 23:25, Milan Zamazal wrote:\n> From: Xander Pronk <xander.c.pronk@gmail.com>\n> \n> Add support for passing the LSC table from debayerParams to the shaders.\n> \n> The LSC table values are floats, we must add `type' parameter to\n> createTexture2D to support this.  Moreover, we use 16-bit internal\n> format for the values, primarily because this works for me, unlike\n> 32-bit floats.\n> \n> When LSC is disabled by the runtime control, we provide a constant 1.0\n> correction table, i.e. a no-op table.  This is preferred to having a\n> runtime flag, to not disturb GPU computation with runtime switches,\n> assuming that disabling LSC in runtime is not a common use case.\n> \n> Co-developed-by: Rick ten Wolde <rick_libcamera@wolde.info>\n> Signed-off-by: Rick ten Wolde <rick_libcamera@wolde.info>\n> Signed-off-by: Xander Pronk <xander.c.pronk@gmail.com>\n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> ---\n>   include/libcamera/internal/egl.h              |  6 +++-\n>   .../internal/software_isp/debayer_params.h    |  2 ++\n>   src/ipa/simple/algorithms/lsc.cpp             | 11 ++++---\n>   src/libcamera/egl.cpp                         | 10 +++++--\n>   src/libcamera/software_isp/debayer.cpp        |  5 ++++\n>   src/libcamera/software_isp/debayer_egl.cpp    | 29 +++++++++++++++++--\n>   src/libcamera/software_isp/debayer_egl.h      |  6 ++++\n>   7 files changed, 60 insertions(+), 9 deletions(-)\n> \n> diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h\n> index 030c813a5..37da2b18a 100644\n> --- a/include/libcamera/internal/egl.h\n> +++ b/include/libcamera/internal/egl.h\n> @@ -107,7 +107,11 @@ public:\n> \n>   \tint createInputDMABufTexture2D(eGLImage &eglImage, int fd);\n>   \tint createOutputDMABufTexture2D(eGLImage &eglImage, int fd);\n> -\tvoid createTexture2D(eGLImage &eglImage, void *data, GLint filter);\n> +\tvoid createTexture2D(eGLImage &eglImage,\n> +\t\t\t     GLint internalFormat,\n> +\t\t\t     GLenum type,\n> +\t\t\t     const void *data,\n> +\t\t\t     GLint filter);\n> \n>   \tvoid pushEnv(std::vector<std::string> &shaderEnv, const char *str);\n>   \tvoid makeCurrent();\n> diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h\n> index e3e01bc04..76825e6c8 100644\n> --- a/include/libcamera/internal/software_isp/debayer_params.h\n> +++ b/include/libcamera/internal/software_isp/debayer_params.h\n> @@ -29,6 +29,8 @@ struct DebayerParams {\n> \n>   \tstatic constexpr unsigned int kLscGridSize = 16;\n>   \tstatic constexpr unsigned int kLscValuesPerCell = 3;\n> +\tstatic constexpr unsigned int kLscBytesPerCell =\n> +\t\tkLscValuesPerCell * sizeof(float);\n>   \tusing LscLookupTable =\n>   \t\tstd::array<float, kLscGridSize * kLscGridSize * kLscValuesPerCell>;\n>   \tLscLookupTable lscLut{};\n> diff --git a/src/ipa/simple/algorithms/lsc.cpp b/src/ipa/simple/algorithms/lsc.cpp\n> index c531937c7..51c5b63d5 100644\n> --- a/src/ipa/simple/algorithms/lsc.cpp\n> +++ b/src/ipa/simple/algorithms/lsc.cpp\n> @@ -46,13 +46,16 @@ void Lsc::prepare([[maybe_unused]] IPAContext &context,\n>   \t\t  IPAFrameContext &frameContext,\n>   \t\t  DebayerParams *params)\n>   {\n> -\tparams->lscEnabled = frameContext.lsc.enabled;\n> -\n>   \tunsigned int ct = frameContext.awb.colourTemperature;\n>   \tconstexpr unsigned int minTemperatureChange = 100;\n> \n> -\tif (!frameContext.lsc.enabled ||\n> -\t    utils::abs_diff(ct, lastAppliedCt_) < minTemperatureChange)\n> +\tif (!frameContext.lsc.enabled) {\n> +\t\tparams->lscLut.fill(1.0);\n> +\t\tlastAppliedCt_ = 0;\n> +\t\treturn;\n> +\t}\n> +\n> +\tif (utils::abs_diff(ct, lastAppliedCt_) < minTemperatureChange)\n>   \t\treturn;\n> \n>   \tconst lsc::Components<uint8_t> &set = lscAlgo_.interpolateComponents(ct);\n> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp\n> index aeac5d313..c2a158ce7 100644\n> --- a/src/libcamera/egl.cpp\n> +++ b/src/libcamera/egl.cpp\n> @@ -241,6 +241,8 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)\n>   /**\n>    * \\brief Create a 2D texture from a memory buffer\n>    * \\param[in,out] eglImage EGL image to associate with the texture\n> + * \\param[in] internalFormat OpenGL internal storage format (e.g., GL_RGB8, GL_RGBA8)\n> + * \\param[in] type OpenGL pixel data type (e.g., GL_UNSIGNED_BYTE, GL_FLOAT)\n>    * \\param[in] data Pointer to pixel data, or nullptr for uninitialised texture\n>    * \\param[in] filter GL texture filter setting\n>    *\n> @@ -249,7 +251,11 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)\n>    * is useful for uploading static data like lookup tables or uniform color\n>    * matrices to the GPU.\n>    */\n> -void eGL::createTexture2D(eGLImage &eglImage, void *data, GLint filter)\n> +void eGL::createTexture2D(eGLImage &eglImage,\n> +\t\t\t  GLint internalFormat,\n> +\t\t\t  GLenum type,\n> +\t\t\t  const void *data,\n> +\t\t\t  GLint filter)\n>   {\n>   \tASSERT(tid_ == Thread::currentId());\n> \n> @@ -257,7 +263,7 @@ void eGL::createTexture2D(eGLImage &eglImage, void *data, GLint filter)\n>   \tglBindTexture(GL_TEXTURE_2D, eglImage.texture_);\n> \n>   \t// Generate texture, bind, associate image to texture, configure, unbind\n> -\tglTexImage2D(GL_TEXTURE_2D, 0, eglImage.format_, eglImage.width_, eglImage.height_, 0, eglImage.format_, GL_UNSIGNED_BYTE, data);\n> +\tglTexImage2D(GL_TEXTURE_2D, 0, internalFormat, eglImage.width_, eglImage.height_, 0, eglImage.format_, type, data);\n> \n>   \t// Nearest filtering\n>   \tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);\n> diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp\n> index 5ae9f032f..70c0e3336 100644\n> --- a/src/libcamera/software_isp/debayer.cpp\n> +++ b/src/libcamera/software_isp/debayer.cpp\n> @@ -53,6 +53,11 @@ namespace libcamera {\n>    * \\brief Number of pixel values per each of the lens shading grid areas\n>    */\n> \n> +/**\n> + * \\var DebayerParams::kLscBytesPerCell\n> + * \\brief Number of bytes per each of the lens shading grid areas\n> + */\n> +\n>   /**\n>    * \\typedef DebayerParams::LscLookupTable\n>    * \\brief Lookup table for lens shading correction\n> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> index 562e9fc7a..0fdf0e6e8 100644\n> --- a/src/libcamera/software_isp/debayer_egl.cpp\n> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> @@ -128,6 +128,8 @@ int DebayerEGL::getShaderVariableLocations(void)\n>   \ttextureUniformBayerFirstRed_ = glGetUniformLocation(programId_, \"tex_bayer_first_red\");\n>   \ttextureUniformProjMatrix_ = glGetUniformLocation(programId_, \"proj_matrix\");\n> \n> +\ttextureUniformLsc_ = glGetUniformLocation(programId_, \"lsc_tex\");\n> +\n>   \tLOG(Debayer, Debug) << \"vertexIn \" << attributeVertex_ << \" textureIn \" << attributeTexture_\n>   \t\t\t    << \" tex_y \" << textureUniformBayerDataIn_\n>   \t\t\t    << \" awb \" << awbUniformDataIn_\n> @@ -139,7 +141,8 @@ int DebayerEGL::getShaderVariableLocations(void)\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> +\t\t\t    << \" proj_matrix \" << textureUniformProjMatrix_\n> +\t\t\t    << \" tex_lsc \" << textureUniformLsc_;\n>   \treturn 0;\n>   }\n> \n> @@ -156,6 +159,9 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm\n>   \t/* Specify GL_OES_EGL_image_external */\n>   \tegl_.pushEnv(shaderEnv, \"#extension GL_OES_EGL_image_external: enable\");\n> \n> +\tif (lscEnabled_)\n> +\t\tegl_.pushEnv(shaderEnv, \"#define APPLY_LSC\");\n> +\n>   \t/*\n>   \t * Tell shaders how to re-order output taking account of how the pixels\n>   \t * are actually stored by EGL.\n> @@ -348,6 +354,18 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg,\n>   \t */\n>   \tstats_->setWindow(Rectangle(window_.size()));\n> \n> +\tif (lscEnabled_) {\n> +\t\tconstexpr unsigned int gridSize = DebayerParams::kLscGridSize;\n> +\t\tconst unsigned int stride = gridSize * DebayerParams::kLscBytesPerCell;\n> +\t\teglImageLscLookup_ =\n> +\t\t\tstd::make_unique<eGLImage>(GL_RGB,\n> +\t\t\t\t\t\t   gridSize,\n> +\t\t\t\t\t\t   gridSize,\n> +\t\t\t\t\t\t   stride,\n> +\t\t\t\t\t\t   GL_TEXTURE2,\n> +\t\t\t\t\t\t   2);\n> +\t}\n> +\n>   \treturn 0;\n>   }\n> \n> @@ -483,6 +501,12 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>   \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_TRUE, params.combinedMatrix.data().data());\n>   \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;\n> \n> +\tif (lscEnabled_) {\n> +\t\tegl_.createTexture2D(*eglImageLscLookup_, GL_RGB16F, GL_FLOAT,\n> +\t\t\t\t     params.lscLut.data(), GL_LINEAR);\n\nAs we are discussing in the multi-pass thread, GL_RGB16F is dependent on \nthe optional GL_EXT_color_buffer_half_float\n\nhttps://registry.khronos.org/OpenGL/extensions/EXT/EXT_color_buffer_half_float.txt\n\nI think it should be pretty easy to disjunct on that as a flag in the \nbase class - a flag I plan to add for SSBO stats but also perfectly \nhappy for you to add.\n\nHalf float linear filtering requires OES_texture_half_float_linear\n\nglGetString(GL_EXTENSIONS) | grep OES_texture_half_float_linear | \ndebayer_egl{ bool _has_OES_texture_half_float_linear;} or whatever\n\nif (_has_OES_texture_half_float_linear)\n\tGL_RGB16F;\n\nCould we repreent the LSC data as uint8 natively ? I mean without \nstoring it all as float and then converting to uint8 on each LSC \napplication cycle ?\n\n> +\t\tglUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_);\n> +\t}\n> +\n>   \t/*\n>   \t * 0 = Red, 1 = Green, 2 = Blue\n>   \t */\n> @@ -530,7 +554,8 @@ int DebayerEGL::debayerGPU(FrameBuffer *input, FrameBuffer *output, const Debaye\n>   \t\t\tLOG(Debayer, Error) << \"mmap-ing buffer(s) failed\";\n>   \t\t\treturn -ENODEV;\n>   \t\t}\n> -\t\tegl_.createTexture2D(*eglImageBayerIn_, inMapped->value().planes()[0].data(), GL_NEAREST);\n> +\t\tegl_.createTexture2D(*eglImageBayerIn_, glFormat_, GL_UNSIGNED_BYTE,\n> +\t\t\t\t     inMapped->value().planes()[0].data(), GL_NEAREST);\n>   \t}\n> \n>   \t/* Generate the output render framebuffer as render to texture */\n> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h\n> index 82ed1305d..f3913d564 100644\n> --- a/src/libcamera/software_isp/debayer_egl.h\n> +++ b/src/libcamera/software_isp/debayer_egl.h\n> @@ -78,7 +78,10 @@ private:\n>   \tstd::unique_ptr<eGLImage> eglImageBayerIn_;\n>   \tstd::unique_ptr<eGLImage> eglImageBayerOut_;\n> \n> +\t/* LSC lookup table */\n> +\tstd::unique_ptr<eGLImage> eglImageLscLookup_;\n>   \tbool lscEnabled_;\n> +\n>   \t/* Shader parameters */\n>   \tfloat firstRed_x_;\n>   \tfloat firstRed_y_;\n> @@ -95,6 +98,9 @@ private:\n>   \t/* Per-frame AWB gains */\n>   \tGLint awbUniformDataIn_;\n> \n> +\t/* Lens shading correction */\n> +\tGLint textureUniformLsc_;\n> +\n>   \t/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */\n>   \tGLint ccmUniformDataIn_;\n> \n> --\n> 2.55.0\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 9151ABF415\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 20 Jul 2026 10:56:33 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7E75266151;\n\tMon, 20 Jul 2026 12:56:32 +0200 (CEST)","from mail-10625.protonmail.ch (mail-10625.protonmail.ch\n\t[79.135.106.25])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 20A9066122\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jul 2026 12:56:31 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxsw.ie header.i=@nxsw.ie header.b=\"k9ONQ+3m\";\n\tdkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxsw.ie;\n\ts=protonmail; t=1784544987; x=1784804187;\n\tbh=SJtYhEDbbPp7HLuzyzQIGrUb7PtoTD09cYcep/OrdjA=;\n\th=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References:\n\tFeedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:\n\tMessage-ID:BIMI-Selector;\n\tb=k9ONQ+3m+JAeqfbhAdkzK5uHEU6uXRztRIutkd7wmcSs01H/XbaTLLtuPauKAvX/V\n\t/58Vb/0dxBifCk/KDg7ZSZsbm3q4if9JCERc7xpxBkYRiwSNyCHrld8gYkhD2ELOHy\n\toBGtn/ZRVN73qNxdXCFf80CxK1yjzFN86I6CXnU9DK7sjCLtM4dHj5DeytloxMgBn0\n\tQ/9U6Ndz+3Se3tx+5jmENB7kUAB1L/9JSRIrjQ8lwWX3VAK89GqkD1kc40ySmEW40C\n\tKkSY8cE6BVuoYx9gvQ5VvIdKUIFekOngjuyFO9TPQILKEp7HTerfOCAGB1dY9E9+RJ\n\tPaSPaghpZIkLw==","Date":"Mon, 20 Jul 2026 10:56:21 +0000","To":"Milan Zamazal <mzamazal@redhat.com>, libcamera-devel@lists.libcamera.org","From":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Cc":"Xander Pronk <xander.c.pronk@gmail.com>,\n\tHans de Goede <johannes.goede@oss.qualcomm.com>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tRick ten Wolde <rick_libcamera@wolde.info>","Subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add LSC\n\tsupport","Message-ID":"<73ffa103-4246-4fb2-9fce-cf18e863999c@nxsw.ie>","In-Reply-To":"<20260716222515.251464-7-mzamazal@redhat.com>","References":"<20260716222515.251464-1-mzamazal@redhat.com>\n\t<20260716222515.251464-7-mzamazal@redhat.com>","Feedback-ID":"136405006:user:proton","X-Pm-Message-ID":"884c43ae720f33ec99cebab42621a7aba3cfe574","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","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":39760,"web_url":"https://patchwork.libcamera.org/comment/39760/","msgid":"<864b0a29-ddd0-4f84-a7ca-da5ea96f6807@nxsw.ie>","date":"2026-07-20T11:07:30","subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add LSC\n\tsupport","submitter":{"id":226,"url":"https://patchwork.libcamera.org/api/people/226/","name":"Bryan O'Donoghue","email":"bod.linux@nxsw.ie"},"content":"On 16/07/2026 23:25, Milan Zamazal wrote:\n> @@ -483,6 +501,12 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>   \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_TRUE, params.combinedMatrix.data().data());\n>   \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;\n> \n> +\tif (lscEnabled_) {\n> +\t\tegl_.createTexture2D(*eglImageLscLookup_, GL_RGB16F, GL_FLOAT,\n> +\t\t\t\t     params.lscLut.data(), GL_LINEAR);\n> +\t\tglUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_);\n> +\t}\n> +\n\nCreate texture should happen in configure() and we should use \negl_.updateTexture2D - if and only if the LSC algorithm has called for \nnew data - else it is sufficient to create and populate the texture and \nthen reuse the texture_id on subsequent passes.\n\nI guess ? LSC doesn't need to be updated for each frame - even if it \ndoes updateTexture2D should be used - as its role in life is to update a \nGPU texture we already have instead of nuking and replacing.\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 1F3A2BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 20 Jul 2026 11:07:36 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3B0A567E30;\n\tMon, 20 Jul 2026 13:07:35 +0200 (CEST)","from mail-24421.protonmail.ch (mail-24421.protonmail.ch\n\t[109.224.244.21])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 49E1C66122\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jul 2026 13:07:34 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxsw.ie header.i=@nxsw.ie header.b=\"elGVCUVY\";\n\tdkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxsw.ie;\n\ts=protonmail; t=1784545653; x=1784804853;\n\tbh=vEjLH5LpzSIMgkj6/6BO4ZSnDf1MIroRTUM3IWAmS1A=;\n\th=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References:\n\tFeedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:\n\tMessage-ID:BIMI-Selector;\n\tb=elGVCUVYUQTP/b5JxiFb4L1jU2LQKR83jV6c6KTea0xW/JJo3qzKIWmxXnrMWA1cp\n\tsJw5YH9YPCoz/zlmeJ0ChQ4DFzlBYdzTXIydc1sl9j77wEpnDIbcYQskQczQ/oVmAw\n\tvCnihlQtAXpMbrTC7Z9zodpTcOli/UL0H8snjXBY+k+e4BChwuwT0B2T0FqU3RKHS5\n\tl3FsI9pUFmWRrQlwqTavXU1s6rkw+I6idh6/hL//Nrbsd2cBSfAKe6IJdGiRX85R6t\n\tNVOnojxe9920nAG09zvUPyGL1lE9DLyTJSdxSCDtX2ex7TwxJN/Kiuh1MjDXadatC2\n\tetRHZK9nSmS2A==","Date":"Mon, 20 Jul 2026 11:07:30 +0000","To":"Milan Zamazal <mzamazal@redhat.com>, libcamera-devel@lists.libcamera.org","From":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Cc":"Xander Pronk <xander.c.pronk@gmail.com>,\n\tHans de Goede <johannes.goede@oss.qualcomm.com>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tRick ten Wolde <rick_libcamera@wolde.info>","Subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add LSC\n\tsupport","Message-ID":"<864b0a29-ddd0-4f84-a7ca-da5ea96f6807@nxsw.ie>","In-Reply-To":"<20260716222515.251464-7-mzamazal@redhat.com>","References":"<20260716222515.251464-1-mzamazal@redhat.com>\n\t<20260716222515.251464-7-mzamazal@redhat.com>","Feedback-ID":"136405006:user:proton","X-Pm-Message-ID":"d7e361c79429709b85c7631654b99a65cd712d8f","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","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":39765,"web_url":"https://patchwork.libcamera.org/comment/39765/","msgid":"<85h5ltkclx.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-07-20T13:35:38","subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add\n\tLSC support","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Bryan O'Donoghue <bod.linux@nxsw.ie> writes:\n\n> On 16/07/2026 23:25, Milan Zamazal wrote:\n>> From: Xander Pronk <xander.c.pronk@gmail.com>\n>> \n>\n>> Add support for passing the LSC table from debayerParams to the shaders.\n>> \n>> The LSC table values are floats, we must add `type' parameter to\n>> createTexture2D to support this.  Moreover, we use 16-bit internal\n>> format for the values, primarily because this works for me, unlike\n>> 32-bit floats.\n>> \n>> When LSC is disabled by the runtime control, we provide a constant 1.0\n>> correction table, i.e. a no-op table.  This is preferred to having a\n>> runtime flag, to not disturb GPU computation with runtime switches,\n>> assuming that disabling LSC in runtime is not a common use case.\n>> \n>> Co-developed-by: Rick ten Wolde <rick_libcamera@wolde.info>\n>> Signed-off-by: Rick ten Wolde <rick_libcamera@wolde.info>\n>> Signed-off-by: Xander Pronk <xander.c.pronk@gmail.com>\n>> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n>> ---\n>>   include/libcamera/internal/egl.h              |  6 +++-\n>>   .../internal/software_isp/debayer_params.h    |  2 ++\n>>   src/ipa/simple/algorithms/lsc.cpp             | 11 ++++---\n>>   src/libcamera/egl.cpp                         | 10 +++++--\n>>   src/libcamera/software_isp/debayer.cpp        |  5 ++++\n>>   src/libcamera/software_isp/debayer_egl.cpp    | 29 +++++++++++++++++--\n>>   src/libcamera/software_isp/debayer_egl.h      |  6 ++++\n>>   7 files changed, 60 insertions(+), 9 deletions(-)\n>> \n>> diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h\n>> index 030c813a5..37da2b18a 100644\n>> --- a/include/libcamera/internal/egl.h\n>> +++ b/include/libcamera/internal/egl.h\n>> @@ -107,7 +107,11 @@ public:\n>> \n>>   \tint createInputDMABufTexture2D(eGLImage &eglImage, int fd);\n>>   \tint createOutputDMABufTexture2D(eGLImage &eglImage, int fd);\n>> -\tvoid createTexture2D(eGLImage &eglImage, void *data, GLint filter);\n>> +\tvoid createTexture2D(eGLImage &eglImage,\n>> +\t\t\t     GLint internalFormat,\n>> +\t\t\t     GLenum type,\n>> +\t\t\t     const void *data,\n>> +\t\t\t     GLint filter);\n>> \n>>   \tvoid pushEnv(std::vector<std::string> &shaderEnv, const char *str);\n>>   \tvoid makeCurrent();\n>> diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h\n>> index e3e01bc04..76825e6c8 100644\n>> --- a/include/libcamera/internal/software_isp/debayer_params.h\n>> +++ b/include/libcamera/internal/software_isp/debayer_params.h\n>> @@ -29,6 +29,8 @@ struct DebayerParams {\n>> \n>>   \tstatic constexpr unsigned int kLscGridSize = 16;\n>>   \tstatic constexpr unsigned int kLscValuesPerCell = 3;\n>> +\tstatic constexpr unsigned int kLscBytesPerCell =\n>> +\t\tkLscValuesPerCell * sizeof(float);\n>>   \tusing LscLookupTable =\n>>   \t\tstd::array<float, kLscGridSize * kLscGridSize * kLscValuesPerCell>;\n>>   \tLscLookupTable lscLut{};\n>> diff --git a/src/ipa/simple/algorithms/lsc.cpp b/src/ipa/simple/algorithms/lsc.cpp\n>> index c531937c7..51c5b63d5 100644\n>> --- a/src/ipa/simple/algorithms/lsc.cpp\n>> +++ b/src/ipa/simple/algorithms/lsc.cpp\n>> @@ -46,13 +46,16 @@ void Lsc::prepare([[maybe_unused]] IPAContext &context,\n>>   \t\t  IPAFrameContext &frameContext,\n>>   \t\t  DebayerParams *params)\n>>   {\n>> -\tparams->lscEnabled = frameContext.lsc.enabled;\n>> -\n>>   \tunsigned int ct = frameContext.awb.colourTemperature;\n>>   \tconstexpr unsigned int minTemperatureChange = 100;\n>> \n>> -\tif (!frameContext.lsc.enabled ||\n>> -\t    utils::abs_diff(ct, lastAppliedCt_) < minTemperatureChange)\n>> +\tif (!frameContext.lsc.enabled) {\n>> +\t\tparams->lscLut.fill(1.0);\n>> +\t\tlastAppliedCt_ = 0;\n>> +\t\treturn;\n>> +\t}\n>> +\n>> +\tif (utils::abs_diff(ct, lastAppliedCt_) < minTemperatureChange)\n>>   \t\treturn;\n>> \n>>   \tconst lsc::Components<uint8_t> &set = lscAlgo_.interpolateComponents(ct);\n>> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp\n>> index aeac5d313..c2a158ce7 100644\n>> --- a/src/libcamera/egl.cpp\n>> +++ b/src/libcamera/egl.cpp\n>> @@ -241,6 +241,8 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)\n>>   /**\n>>    * \\brief Create a 2D texture from a memory buffer\n>>    * \\param[in,out] eglImage EGL image to associate with the texture\n>> + * \\param[in] internalFormat OpenGL internal storage format (e.g., GL_RGB8, GL_RGBA8)\n>> + * \\param[in] type OpenGL pixel data type (e.g., GL_UNSIGNED_BYTE, GL_FLOAT)\n>>    * \\param[in] data Pointer to pixel data, or nullptr for uninitialised texture\n>>    * \\param[in] filter GL texture filter setting\n>>    *\n>> @@ -249,7 +251,11 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)\n>>    * is useful for uploading static data like lookup tables or uniform color\n>>    * matrices to the GPU.\n>>    */\n>> -void eGL::createTexture2D(eGLImage &eglImage, void *data, GLint filter)\n>> +void eGL::createTexture2D(eGLImage &eglImage,\n>> +\t\t\t  GLint internalFormat,\n>> +\t\t\t  GLenum type,\n>> +\t\t\t  const void *data,\n>> +\t\t\t  GLint filter)\n>>   {\n>>   \tASSERT(tid_ == Thread::currentId());\n>> \n>> @@ -257,7 +263,7 @@ void eGL::createTexture2D(eGLImage &eglImage, void *data, GLint filter)\n>>   \tglBindTexture(GL_TEXTURE_2D, eglImage.texture_);\n>> \n>>   \t// Generate texture, bind, associate image to texture, configure, unbind\n>> -\tglTexImage2D(GL_TEXTURE_2D, 0, eglImage.format_, eglImage.width_, eglImage.height_, 0, eglImage.format_, GL_UNSIGNED_BYTE, data);\n>> +\tglTexImage2D(GL_TEXTURE_2D, 0, internalFormat, eglImage.width_, eglImage.height_, 0, eglImage.format_, type, data);\n>> \n>>   \t// Nearest filtering\n>>   \tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);\n>> diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp\n>> index 5ae9f032f..70c0e3336 100644\n>> --- a/src/libcamera/software_isp/debayer.cpp\n>> +++ b/src/libcamera/software_isp/debayer.cpp\n>> @@ -53,6 +53,11 @@ namespace libcamera {\n>>    * \\brief Number of pixel values per each of the lens shading grid areas\n>>    */\n>> \n>> +/**\n>> + * \\var DebayerParams::kLscBytesPerCell\n>> + * \\brief Number of bytes per each of the lens shading grid areas\n>> + */\n>> +\n>>   /**\n>>    * \\typedef DebayerParams::LscLookupTable\n>>    * \\brief Lookup table for lens shading correction\n>> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n>> index 562e9fc7a..0fdf0e6e8 100644\n>> --- a/src/libcamera/software_isp/debayer_egl.cpp\n>> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n>> @@ -128,6 +128,8 @@ int DebayerEGL::getShaderVariableLocations(void)\n>>   \ttextureUniformBayerFirstRed_ = glGetUniformLocation(programId_, \"tex_bayer_first_red\");\n>>   \ttextureUniformProjMatrix_ = glGetUniformLocation(programId_, \"proj_matrix\");\n>> \n>> +\ttextureUniformLsc_ = glGetUniformLocation(programId_, \"lsc_tex\");\n>> +\n>>   \tLOG(Debayer, Debug) << \"vertexIn \" << attributeVertex_ << \" textureIn \" << attributeTexture_\n>>   \t\t\t    << \" tex_y \" << textureUniformBayerDataIn_\n>>   \t\t\t    << \" awb \" << awbUniformDataIn_\n>> @@ -139,7 +141,8 @@ int DebayerEGL::getShaderVariableLocations(void)\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>> +\t\t\t    << \" proj_matrix \" << textureUniformProjMatrix_\n>> +\t\t\t    << \" tex_lsc \" << textureUniformLsc_;\n>>   \treturn 0;\n>>   }\n>> \n>> @@ -156,6 +159,9 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm\n>>   \t/* Specify GL_OES_EGL_image_external */\n>>   \tegl_.pushEnv(shaderEnv, \"#extension GL_OES_EGL_image_external: enable\");\n>> \n>> +\tif (lscEnabled_)\n>> +\t\tegl_.pushEnv(shaderEnv, \"#define APPLY_LSC\");\n>> +\n>>   \t/*\n>>   \t * Tell shaders how to re-order output taking account of how the pixels\n>>   \t * are actually stored by EGL.\n>> @@ -348,6 +354,18 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg,\n>>   \t */\n>>   \tstats_->setWindow(Rectangle(window_.size()));\n>> \n>> +\tif (lscEnabled_) {\n>> +\t\tconstexpr unsigned int gridSize = DebayerParams::kLscGridSize;\n>> +\t\tconst unsigned int stride = gridSize * DebayerParams::kLscBytesPerCell;\n>> +\t\teglImageLscLookup_ =\n>> +\t\t\tstd::make_unique<eGLImage>(GL_RGB,\n>> +\t\t\t\t\t\t   gridSize,\n>> +\t\t\t\t\t\t   gridSize,\n>> +\t\t\t\t\t\t   stride,\n>> +\t\t\t\t\t\t   GL_TEXTURE2,\n>> +\t\t\t\t\t\t   2);\n>> +\t}\n>> +\n>>   \treturn 0;\n>>   }\n>> \n>> @@ -483,6 +501,12 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>>   \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_TRUE, params.combinedMatrix.data().data());\n>>   \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;\n>> \n>> +\tif (lscEnabled_) {\n>> +\t\tegl_.createTexture2D(*eglImageLscLookup_, GL_RGB16F, GL_FLOAT,\n>> +\t\t\t\t     params.lscLut.data(), GL_LINEAR);\n>\n> As we are discussing in the multi-pass thread, GL_RGB16F is dependent on \n> the optional GL_EXT_color_buffer_half_float\n>\n> https://registry.khronos.org/OpenGL/extensions/EXT/EXT_color_buffer_half_float.txt\n>\n> I think it should be pretty easy to disjunct on that as a flag in the \n> base class - a flag I plan to add for SSBO stats but also perfectly \n> happy for you to add.\n>\n> Half float linear filtering requires OES_texture_half_float_linear\n>\n> glGetString(GL_EXTENSIONS) | grep OES_texture_half_float_linear | \n> debayer_egl{ bool _has_OES_texture_half_float_linear;} or whatever\n>\n> if (_has_OES_texture_half_float_linear)\n> \tGL_RGB16F;\n>\n> Could we repreent the LSC data as uint8 natively ? I mean without \n> storing it all as float and then converting to uint8 on each LSC \n> application cycle ?\n\nWe could.  `float' would be a nice and clear interface.  But I'd prefer\nnot to deal with conditional support, especially if we had to handle the\nunsupported case some way.  Since we opt for UQ<2,6> with libipa in the\nalgorithm part, we can pass that to debayering.  It may become a\nlimitation in the future, but for now, why not, it's not that difficult\nto change once/if needed.\n\n>> +\t\tglUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_);\n>> +\t}\n>> +\n>>   \t/*\n>>   \t * 0 = Red, 1 = Green, 2 = Blue\n>>   \t */\n>> @@ -530,7 +554,8 @@ int DebayerEGL::debayerGPU(FrameBuffer *input, FrameBuffer *output, const Debaye\n>>   \t\t\tLOG(Debayer, Error) << \"mmap-ing buffer(s) failed\";\n>>   \t\t\treturn -ENODEV;\n>>   \t\t}\n>> -\t\tegl_.createTexture2D(*eglImageBayerIn_, inMapped->value().planes()[0].data(), GL_NEAREST);\n>> +\t\tegl_.createTexture2D(*eglImageBayerIn_, glFormat_, GL_UNSIGNED_BYTE,\n>> +\t\t\t\t     inMapped->value().planes()[0].data(), GL_NEAREST);\n>>   \t}\n>> \n>>   \t/* Generate the output render framebuffer as render to texture */\n>> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h\n>> index 82ed1305d..f3913d564 100644\n>> --- a/src/libcamera/software_isp/debayer_egl.h\n>> +++ b/src/libcamera/software_isp/debayer_egl.h\n>> @@ -78,7 +78,10 @@ private:\n>>   \tstd::unique_ptr<eGLImage> eglImageBayerIn_;\n>>   \tstd::unique_ptr<eGLImage> eglImageBayerOut_;\n>> \n>> +\t/* LSC lookup table */\n>> +\tstd::unique_ptr<eGLImage> eglImageLscLookup_;\n>>   \tbool lscEnabled_;\n>> +\n>>   \t/* Shader parameters */\n>>   \tfloat firstRed_x_;\n>>   \tfloat firstRed_y_;\n>> @@ -95,6 +98,9 @@ private:\n>>   \t/* Per-frame AWB gains */\n>>   \tGLint awbUniformDataIn_;\n>> \n>> +\t/* Lens shading correction */\n>> +\tGLint textureUniformLsc_;\n>> +\n>>   \t/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */\n>>   \tGLint ccmUniformDataIn_;\n>> \n>> --\n>> 2.55.0\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 F276AC328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 20 Jul 2026 13:35:48 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1D96567E42;\n\tMon, 20 Jul 2026 15:35:48 +0200 (CEST)","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 101C066177\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jul 2026 15:35:46 +0200 (CEST)","from mail-lf1-f72.google.com (mail-lf1-f72.google.com\n\t[209.85.167.72]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-623-3NgnAAzkOTedEzmXiwhEEg-1; Mon, 20 Jul 2026 09:35:43 -0400","by mail-lf1-f72.google.com with SMTP id\n\t2adb3069b0e04-5aeb49bb645so4172033e87.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jul 2026 06:35:42 -0700 (PDT)","from mzamazal-thinkpadp1gen7.tpbc.csb\n\t(ip-77-48-47-4.net.vodafone.cz. [77.48.47.4])\n\tby smtp.gmail.com with ESMTPSA id\n\t2adb3069b0e04-5b291d98301sm2304071e87.25.2026.07.20.06.35.38\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 20 Jul 2026 06:35:39 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"U6LI0lO3\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1784554546;\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=mSLTYTKG4pGZtaR+C3XE0EECQzuoUj1RljLAA1uifl0=;\n\tb=U6LI0lO3j6wNZVysiMHTzCeWi0r7Igg/zYTO76/EPgH2/tdVhyQTEtCtwdQk4V6MgqcohG\n\tKtrklwlx55QNsgmsmPLV1M4d7yD/VVbmxhLFz5cxX1bvAh24t7KOlV4ZRmb9iFT3meUxnc\n\tnXaZvptlJBgd7JF9NzO0KyOv0Ox88J0=","X-MC-Unique":"3NgnAAzkOTedEzmXiwhEEg-1","X-Mimecast-MFC-AGG-ID":"3NgnAAzkOTedEzmXiwhEEg_1784554541","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1784554541; x=1785159341;\n\th=content-type:mime-version:user-agent:message-id:date:references\n\t:in-reply-to:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to\n\t:cc:subject:date:message-id:reply-to:content-type;\n\tbh=mSLTYTKG4pGZtaR+C3XE0EECQzuoUj1RljLAA1uifl0=;\n\tb=rlg3aVHURYCe615QbgfbBXpNIdt8AsCHQrKg2AF5k6srDA7xxpx06//04R8qheOPMr\n\tG7luD5qlDPQKqGptPGPrPiYcqZnFVBBta9g3XcPB6W4+o55cUW1vvjM+maZdo/Mp7WlL\n\tYnnwEI5/rei3TE1TfNYB8ct/0kw8hLRC2JsOj5DQK3KS9GGhPTPnOzKb6Iic0AOmoj2o\n\tB7FidjxjpechGmqOsVhH8K6hmztPvtaJU5vuQhtqGHamf0Q8YnM9UVdAcGAHsRhcAeMC\n\tIOXhwO/oaToAZeg5UUQHOvUCfZpjk2tyW8OcYEtoWQhwY9ZTO1bqcb+3kAcIs3TME2Uy\n\tCySA==","X-Gm-Message-State":"AOJu0Yw4WyCzVMSeFee5XyWPK3cEjWSwNHRJ9XcgF5a17cZ3+qpZtIGD\n\tbDjuLdPU1JnLPcglKS9iKon7ObEOhFPVCIma9WoioZElSLbv7hKfXlRTOoF+X+eOkHaVMs5kRuP\n\te6URuJ/b4NvmKoCb5Y/pYPfU+4pYn6zIwSw6rhfNz4Gj06YbJWzEcEka0u45KOEs80visSDpq0F\n\tY=","X-Gm-Gg":"AfdE7ckIgGZhhxRQzedIQxTg4JofQXwsP9pp7zC5xrA8iRgwzllqeqazw6tqPzShT1r\n\tRWIsEdk6l7aSUvtsl028bOSByPjo3PufAO731k+InwBxb9XUckYlqkmmGO25PICU7hQj8Wic8Ro\n\tMAv54rbB85ljOVaRLuVkeg8f4wkLMz+i4cfe+C2aDzknlf5wC5ToxLcF120FIQMX0SSoDX1Dcwr\n\tjJUhn7C7OKlBbnRflCMrUAcszIAjddUDSCrhZm8qCsug5u1WGAKas4XJeMQZmNadD5rQsZNnS3W\n\tAnzvp5b64ARllkfEzblQfQCUVT5N0QM7uIz/aF1i/coq/7hAZrxem/sqvKa2qtUhH93ccjCqtIs\n\tSAoPdcBJjYWoD5fkKGL8pafrwMK/H3VLIZ9la3hZEIHotPmwXtktWBA==","X-Received":["by 2002:a05:6512:641a:b0:5b0:eda:de1d with SMTP id\n\t2adb3069b0e04-5b28f874113mr2677399e87.18.1784554540807; \n\tMon, 20 Jul 2026 06:35:40 -0700 (PDT)","by 2002:a05:6512:641a:b0:5b0:eda:de1d with SMTP id\n\t2adb3069b0e04-5b28f874113mr2677389e87.18.1784554540309; \n\tMon, 20 Jul 2026 06:35:40 -0700 (PDT)"],"From":"Milan Zamazal <mzamazal@redhat.com>","To":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Cc":"libcamera-devel@lists.libcamera.org,  Xander Pronk\n\t<xander.c.pronk@gmail.com>,  Hans de Goede\n\t<johannes.goede@oss.qualcomm.com>,  Laurent Pinchart\n\t<laurent.pinchart@ideasonboard.com>,  Rick ten Wolde\n\t<rick_libcamera@wolde.info>","Subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add\n\tLSC support","In-Reply-To":"<73ffa103-4246-4fb2-9fce-cf18e863999c@nxsw.ie> (Bryan\n\tO'Donoghue's message of \"Mon, 20 Jul 2026 10:56:21 +0000\")","References":"<20260716222515.251464-1-mzamazal@redhat.com>\n\t<20260716222515.251464-7-mzamazal@redhat.com>\n\t<73ffa103-4246-4fb2-9fce-cf18e863999c@nxsw.ie>","Date":"Mon, 20 Jul 2026 15:35:38 +0200","Message-ID":"<85h5ltkclx.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":"1wVnwzwq2yoS67HnaX1RPowE6x1rQznp0AWgRsOX9qg_1784554541","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":39766,"web_url":"https://patchwork.libcamera.org/comment/39766/","msgid":"<85cxwhkchn.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-07-20T13:38:12","subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add\n\tLSC support","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Bryan O'Donoghue <bod.linux@nxsw.ie> writes:\n\n> On 16/07/2026 23:25, Milan Zamazal wrote:\n>> @@ -483,6 +501,12 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>>   \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_TRUE, params.combinedMatrix.data().data());\n>>   \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;\n>> \n>> +\tif (lscEnabled_) {\n>> +\t\tegl_.createTexture2D(*eglImageLscLookup_, GL_RGB16F, GL_FLOAT,\n>> +\t\t\t\t     params.lscLut.data(), GL_LINEAR);\n>> +\t\tglUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_);\n>> +\t}\n>> +\n>\n> Create texture should happen in configure() and we should use \n> egl_.updateTexture2D - if and only if the LSC algorithm has called for \n> new data - else it is sufficient to create and populate the texture and \n> then reuse the texture_id on subsequent passes.\n>\n> I guess ? LSC doesn't need to be updated for each frame - even if it \n> does updateTexture2D should be used - as its role in life is to update a \n> GPU texture we already have instead of nuking and replacing.\n\nOK, we have it now so let's use it.  I'll do something about it in v10.","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 9C7EFC328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 20 Jul 2026 13:38:21 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D759A67E42;\n\tMon, 20 Jul 2026 15:38:20 +0200 (CEST)","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 73F1B66177\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jul 2026 15:38:18 +0200 (CEST)","from mail-ed1-f71.google.com (mail-ed1-f71.google.com\n\t[209.85.208.71]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-527-szwcDcL3OUikBsj_-CDGHQ-1; Mon, 20 Jul 2026 09:38:15 -0400","by mail-ed1-f71.google.com with SMTP id\n\t4fb4d7f45d1cf-69841da1946so8085127a12.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jul 2026 06:38:15 -0700 (PDT)","from mzamazal-thinkpadp1gen7.tpbc.csb\n\t(ip-77-48-47-4.net.vodafone.cz. [77.48.47.4])\n\tby smtp.gmail.com with ESMTPSA id\n\ta640c23a62f3a-c1712a63d99sm465538566b.41.2026.07.20.06.38.13\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 20 Jul 2026 06:38:13 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"SBgIP0/2\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1784554697;\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=5toFUi2Q4ZPxnYqurVRxV87K+3P2UyrGCSGPnJlq3QM=;\n\tb=SBgIP0/2sycyIJ7H/7lYfOuPqhhikCqy1uWBUnzeBYC+OY6vhtS0Y2nzbVCGK+9bzX2PlI\n\tq62CgCUbF7ky4yz76jYIz56u9lbXS93ahc9ny8sIW4facXRIo2k6X1qCApxSjYHxzrelVP\n\tbp7UzRDa4yGyUC5JtGnkt7LMZgX1beo=","X-MC-Unique":"szwcDcL3OUikBsj_-CDGHQ-1","X-Mimecast-MFC-AGG-ID":"szwcDcL3OUikBsj_-CDGHQ_1784554695","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1784554694; x=1785159494;\n\th=content-type:mime-version:user-agent:message-id:date:references\n\t:in-reply-to:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to\n\t:cc:subject:date:message-id:reply-to:content-type;\n\tbh=5toFUi2Q4ZPxnYqurVRxV87K+3P2UyrGCSGPnJlq3QM=;\n\tb=r3Sevgncev/jM+qVl3p+fZvMikpCILIAIpKHa3KPoZF8y7vZCGJVtnsbRFvf735f/D\n\tXqFkAxabseXjlvnC9Gg7zmhQ1iuK2f+1F/gTHj/D8bz2ztsLMJYlcihhFf9P0+O6KFfU\n\tPyIZlgxCqwHfYth0oqoK9r3ucqTG3xtwD054aXxeVCbJHKga5Xpq+hY8VKdGs1yGtNyr\n\tMKsa+imoAp3gNdc6jITUYWPhaIthtEWpFx90GtWhJzqbJ/jKOasQz085CzXySBaC831B\n\tVh3od8eQFt9CKUjU81cB9C7FVEDvjaJD0MaTBKfYI/B+YNLW4xzLshpdMBafLN2x/jyc\n\t/d6w==","X-Gm-Message-State":"AOJu0YzPdlvHTec+0cTLJK29QZvGF4Pexb6EshWRvRaJAxmqoEAlGHbp\n\tBV7F5jrK5pZwLFDVJ9GuTjyd07Jnm5227InaXh2f0ojNMFoibWH5VIdvCtVnLTl98v/EAK6xWFV\n\tI31NUJhhwNHdI4B9SFQuX+0ksI+msIdfyCss+EjETao0WbAW2Jq6u6J5Ig7In5WVK6D4+KG13kH\n\t0=","X-Gm-Gg":"AfdE7ckbh3PoxyPqeUw/penZwaPrIq1ljazZquu2qlDg4IPDbRpNjdf1FOSRbO5hQJP\n\tz0miwQyZP6mkEPq3tKYVye6iVq674qgjnA7/DZEgg4dH8lAI5cDRSo+m54qLrmreUe9qcE2e9Rh\n\tkSwhQTfd7VGfn0sLIEQesKYc4f/FNNz/uex07Y9aVpZYhH9EF226oeVClU62owOGYqYcux0S6oz\n\trw0UACAd0gw7K2wDdYnfwFJvs9oD+2CkB5zbh3xs+vKkZ0PwWPYMe/qeQuPIsFY2Uz47rwO+iF9\n\t5ENqM9CxgiqdseLz+LmiqvKQ0ySVbtcimqLgCUuOsCrxlLK1VBLDz5+0ZdbQQa4vbWkYeLZmt/n\n\tkOWqIDC+T/P7xJbadvZgb0d3RkQc4xq+1VN4b5hhyqhOJcZg79brMAg==","X-Received":["by 2002:a17:906:478b:b0:c16:75cc:33a9 with SMTP id\n\ta640c23a62f3a-c16b4754f9dmr665393066b.20.1784554694656; \n\tMon, 20 Jul 2026 06:38:14 -0700 (PDT)","by 2002:a17:906:478b:b0:c16:75cc:33a9 with SMTP id\n\ta640c23a62f3a-c16b4754f9dmr665391866b.20.1784554694295; \n\tMon, 20 Jul 2026 06:38:14 -0700 (PDT)"],"From":"Milan Zamazal <mzamazal@redhat.com>","To":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Cc":"libcamera-devel@lists.libcamera.org,  Xander Pronk\n\t<xander.c.pronk@gmail.com>,  Hans de Goede\n\t<johannes.goede@oss.qualcomm.com>,  Laurent Pinchart\n\t<laurent.pinchart@ideasonboard.com>,  Rick ten Wolde\n\t<rick_libcamera@wolde.info>","Subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add\n\tLSC support","In-Reply-To":"<864b0a29-ddd0-4f84-a7ca-da5ea96f6807@nxsw.ie> (Bryan\n\tO'Donoghue's message of \"Mon, 20 Jul 2026 11:07:30 +0000\")","References":"<20260716222515.251464-1-mzamazal@redhat.com>\n\t<20260716222515.251464-7-mzamazal@redhat.com>\n\t<864b0a29-ddd0-4f84-a7ca-da5ea96f6807@nxsw.ie>","Date":"Mon, 20 Jul 2026 15:38:12 +0200","Message-ID":"<85cxwhkchn.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":"0DJRbKHI1rWNVjgLR3rLbwEfYKHcwe7g7hdzsTuPyGc_1784554695","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":39771,"web_url":"https://patchwork.libcamera.org/comment/39771/","msgid":"<be7e8bbb-1997-4059-b786-1164ad3a2156@nxsw.ie>","date":"2026-07-20T19:47:56","subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add LSC\n\tsupport","submitter":{"id":226,"url":"https://patchwork.libcamera.org/api/people/226/","name":"Bryan O'Donoghue","email":"bod.linux@nxsw.ie"},"content":"On 20/07/2026 14:35, Milan Zamazal wrote:\n>>> @@ -483,6 +501,12 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>>>    \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_TRUE, params.combinedMatrix.data().data());\n>>>    \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;\n>>>\n>>> +\tif (lscEnabled_) {\n>>> +\t\tegl_.createTexture2D(*eglImageLscLookup_, GL_RGB16F, GL_FLOAT,\n>>> +\t\t\t\t     params.lscLut.data(), GL_LINEAR);\n>> As we are discussing in the multi-pass thread, GL_RGB16F is dependent on\n>> the optional GL_EXT_color_buffer_half_float\n>>\n>> https://registry.khronos.org/OpenGL/extensions/EXT/ \n>> EXT_color_buffer_half_float.txt\n>>\n>> I think it should be pretty easy to disjunct on that as a flag in the\n>> base class - a flag I plan to add for SSBO stats but also perfectly\n>> happy for you to add.\n>>\n>> Half float linear filtering requires OES_texture_half_float_linear\n>>\n>> glGetString(GL_EXTENSIONS) | grep OES_texture_half_float_linear |\n>> debayer_egl{ bool _has_OES_texture_half_float_linear;} or whatever\n>>\n>> if (_has_OES_texture_half_float_linear)\n>> \tGL_RGB16F;\n>>\n>> Could we repreent the LSC data as uint8 natively ? I mean without\n>> storing it all as float and then converting to uint8 on each LSC\n>> application cycle ?\n> We could.  `float' would be a nice and clear interface.  But I'd prefer\n> not to deal with conditional support, especially if we had to handle the\n> unsupported case some way.  Since we opt for UQ<2,6> with libipa in the\n> algorithm part, we can pass that to debayering.  It may become a\n> limitation in the future, but for now, why not, it's not that difficult\n> to change once/if needed.\n\nRight so that would fit into eight bits as a regular \nGL_RGB/GL_UNSIGNED_BYTE.\n\nSo long as you do the normalisation in the shader, that should work.\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 9BAC7BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 20 Jul 2026 19:48:04 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0D2CB67E64;\n\tMon, 20 Jul 2026 21:48:03 +0200 (CEST)","from mail-4323.protonmail.ch (mail-4323.protonmail.ch\n\t[185.70.43.23])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DE4E667E44\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jul 2026 21:48:00 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxsw.ie header.i=@nxsw.ie header.b=\"Nidmi1aU\";\n\tdkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxsw.ie;\n\ts=protonmail; t=1784576879; x=1784836079;\n\tbh=mZZYYdagbD1wdznILJAMbJ662JccUMcX8SZmeQs+0fw=;\n\th=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References:\n\tFeedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:\n\tMessage-ID:BIMI-Selector;\n\tb=Nidmi1aUGjsNkt0/OhaCh/VD7chzh8YghzOVLZmfuzLlDffT70qY/kWzBydDteD9X\n\tygMH8iXbtTSCtPCX0LsK0PEPtelaKxIjFPS8osVa5RCitQnJ+7sU8rzW/shqUD4/sn\n\tK2SM6wqwCwbBKIiZHzhFqQWEzF+OK4pqoaWIsW/NAMR0VkLR/IGTRvCmZjIoN5pf8G\n\tNFnr1VeRkF2NoYdBT72UkBTZFO49jKs+pMLPQZmdd7euFXg3KB41vabj1bBKNkMAim\n\tZLJYu7ZKAjmOCL8S+DzUUjNWRK8gkmanEnvVwFqonc53+dmapGfdUKcsYDFubnjAMr\n\tjUy3qCnRx2lgg==","Date":"Mon, 20 Jul 2026 19:47:56 +0000","To":"Milan Zamazal <mzamazal@redhat.com>","From":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Cc":"libcamera-devel@lists.libcamera.org,\n\tXander Pronk <xander.c.pronk@gmail.com>,\n\tHans de Goede <johannes.goede@oss.qualcomm.com>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tRick ten Wolde <rick_libcamera@wolde.info>","Subject":"Re: [RFC PATCH v8 6/6] libcamera: software_isp: debayer_egl: Add LSC\n\tsupport","Message-ID":"<be7e8bbb-1997-4059-b786-1164ad3a2156@nxsw.ie>","In-Reply-To":"<85h5ltkclx.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","References":"<20260716222515.251464-1-mzamazal@redhat.com>\n\t<20260716222515.251464-7-mzamazal@redhat.com>\n\t<73ffa103-4246-4fb2-9fce-cf18e863999c@nxsw.ie>\n\t<85h5ltkclx.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","Feedback-ID":"136405006:user:proton","X-Pm-Message-ID":"06dd9ff5c8424d235030b15ecfa685d6e7a3c065","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","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>"}}]