[{"id":38523,"web_url":"https://patchwork.libcamera.org/comment/38523/","msgid":"<20260408001702.GN1268443@killaraus.ideasonboard.com>","date":"2026-04-08T00:17:02","subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Tue, Apr 07, 2026 at 11:01:08PM +0100, Kieran Bingham wrote:\n> Remove the open coded matrix multiplication as glsl can perform this\n> directly. Adapt the uniform ccmUniformDataIn_ to ensure we correctly\n> upload the matrix in row major ordering.\n> \n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> ---\n>  src/libcamera/shaders/bayer_1x_packed.frag | 45 ++----------------------------\n>  src/libcamera/shaders/bayer_unpacked.frag  | 44 ++---------------------------\n>  src/libcamera/software_isp/debayer_egl.cpp | 12 ++------\n>  3 files changed, 7 insertions(+), 94 deletions(-)\n> \n> diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag\n> index 9a1992e219dd066945b3f46ec509f47a31590385..57f0be9b264bdbdf523291dc9b35ab5fd6c9ef6a 100644\n> --- a/src/libcamera/shaders/bayer_1x_packed.frag\n> +++ b/src/libcamera/shaders/bayer_1x_packed.frag\n> @@ -231,49 +231,8 @@ void main(void)\n>  \t/* Apply AWB gains, and saturate each channel at sensor range */\n>  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n>  \n> -\t/*\n> -\t *   CCM is a 3x3 in the format\n> -\t *\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> -\t *   +--------------+----------------+---------------+\n> -\t *\n> -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> -\t *\n> -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> -\t *\n> -\t *   CPU\n> -\t *   float ccm [] = {\n> -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> -\t *   };\n> -\t *\n> -\t *   GPU\n> -\t *   ccm = {\n> -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> -\t *   }\n> -\t *\n> -\t *   However the indexing for the mat data-type is column major hence\n> -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> -\t *\n> -\t */\n> -\tfloat rin, gin, bin;\n> -\trin = rgb.r;\n> -\tgin = rgb.g;\n> -\tbin = rgb.b;\n> -\n> -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> +\t/* Row major Colour Correction Matrix multiplication */\n\nRow-major is related to how data is stored in memory. When writing\n\n\tccm * rgb\n\nthat's not relevant any more. You can drop it from the comment. Same\nbelow.\n\n> +\trgb = ccm * rgb;\n\nI wonder why that was open-coded. Any idea ? I suppose there's no\nnegative performance impact from this patch, as the compiler should\ngenerate the same or better instructions ?\n\n>  \n>  \t/*\n>  \t * Contrast\n> diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag\n> index 87e4e4915fe19679943fdcc3d213a0224b89065e..52de0a7901cfac33dbc7b306f1840ec0048cd8ea 100644\n> --- a/src/libcamera/shaders/bayer_unpacked.frag\n> +++ b/src/libcamera/shaders/bayer_unpacked.frag\n> @@ -134,49 +134,9 @@ void main(void) {\n>  \t/* Apply AWB gains, and saturate each channel at sensor range */\n>  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n>  \n> -\t/*\n> -\t *   CCM is a 3x3 in the format\n> -\t *\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> -\t *   +--------------+----------------+---------------+\n> -\t *\n> -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> -\t *\n> -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> -\t *\n> -\t *   CPU\n> -\t *   float ccm [] = {\n> -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> -\t *   };\n> -\t *\n> -\t *   GPU\n> -\t *   ccm = {\n> -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> -\t *   }\n> -\t *\n> -\t *   However the indexing for the mat data-type is column major hence\n> -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> -\t *\n> -\t */\n> -\tfloat rin, gin, bin;\n> -\trin = rgb.r;\n> -\tgin = rgb.g;\n> -\tbin = rgb.b;\n>  \n> -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> +\t/* Row major Colour Correction Matrix multiplication */\n> +\trgb = ccm * rgb;\n>  \n>  \t/*\n>  \t * Contrast\n> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> index 738036e649224f370bdf9a0cc59b399f8b1066de..1022f595cc71751cd0c9133b3e5755f591224dc4 100644\n> --- a/src/libcamera/software_isp/debayer_egl.cpp\n> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> @@ -464,15 +464,9 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>  \t\t\t    << \" textureUniformProjMatrix_ \" << textureUniformProjMatrix_;\n>  \n>  \tGLfloat ccm[9] = {\n> -\t\tparams.combinedMatrix[0][0],\n> -\t\tparams.combinedMatrix[0][1],\n> -\t\tparams.combinedMatrix[0][2],\n> -\t\tparams.combinedMatrix[1][0],\n> -\t\tparams.combinedMatrix[1][1],\n> -\t\tparams.combinedMatrix[1][2],\n> -\t\tparams.combinedMatrix[2][0],\n> -\t\tparams.combinedMatrix[2][1],\n> -\t\tparams.combinedMatrix[2][2],\n> +\t\tparams.combinedMatrix[0][0], params.combinedMatrix[1][0], params.combinedMatrix[2][0],\n> +\t\tparams.combinedMatrix[0][1], params.combinedMatrix[1][1], params.combinedMatrix[2][1],\n> +\t\tparams.combinedMatrix[0][2], params.combinedMatrix[1][2], params.combinedMatrix[2][2],\n\nYou're now storing the data in column-major order, ...\n\n>  \t};\n>  \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);\n\n... and the third argument matches that. As the libcamera Matrix class\nstores elements in row-major order, I think it would be clearer to store\nthe data in row-major order in the ccm array as well, and set the third\nargument to GL_TRUE accordingly.\n\nWe could then possibly avoid copying the data to a local array (here or\nas a separate patch).\n\n>  \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;\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 86901BEFBE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  8 Apr 2026 00:17:06 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8E79B62DA7;\n\tWed,  8 Apr 2026 02:17:05 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6D03662CEB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  8 Apr 2026 02:17:04 +0200 (CEST)","from killaraus.ideasonboard.com\n\t(2001-14ba-703d-e500--2a1.rev.dnainternet.fi\n\t[IPv6:2001:14ba:703d:e500::2a1])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 62ABE1121; \n\tWed,  8 Apr 2026 02:15:36 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"cV/zLL9z\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1775607336;\n\tbh=vGvZCBsjVB1z4e82FQzLBGwd1DRouQ3yKjrKkt0Ia5E=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=cV/zLL9z/nSZKBniN3JnCHtjXou7VVxRhnvL5AnsqhL/Yn0kIEiOaJkcY3StS0EXd\n\tlXDBQfj0vAkQBpJ1FdYu6KdLi8xuSbmsYeOWkEa5e1T39n5bGhcM5eQFvjYnEkpJ22\n\tOHZ9XBeqYREGAJrhr/jOpAmgFUI/agWSN1FuW6FY=","Date":"Wed, 8 Apr 2026 03:17:02 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","Message-ID":"<20260408001702.GN1268443@killaraus.ideasonboard.com>","References":"<20260407-kbingham-awb-split-v1-0-a39af3f4dc20@ideasonboard.com>\n\t<20260407-kbingham-awb-split-v1-5-a39af3f4dc20@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20260407-kbingham-awb-split-v1-5-a39af3f4dc20@ideasonboard.com>","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":38535,"web_url":"https://patchwork.libcamera.org/comment/38535/","msgid":"<85mrzdbrm2.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-04-08T11:48:05","subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Laurent Pinchart <laurent.pinchart@ideasonboard.com> writes:\n\n> On Tue, Apr 07, 2026 at 11:01:08PM +0100, Kieran Bingham wrote:\n>> Remove the open coded matrix multiplication as glsl can perform this\n>> directly. Adapt the uniform ccmUniformDataIn_ to ensure we correctly\n>\n>> upload the matrix in row major ordering.\n>> \n>> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n>> ---\n>>  src/libcamera/shaders/bayer_1x_packed.frag | 45 ++----------------------------\n>>  src/libcamera/shaders/bayer_unpacked.frag  | 44 ++---------------------------\n>>  src/libcamera/software_isp/debayer_egl.cpp | 12 ++------\n>>  3 files changed, 7 insertions(+), 94 deletions(-)\n>> \n>> diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag\n>> index 9a1992e219dd066945b3f46ec509f47a31590385..57f0be9b264bdbdf523291dc9b35ab5fd6c9ef6a 100644\n>> --- a/src/libcamera/shaders/bayer_1x_packed.frag\n>> +++ b/src/libcamera/shaders/bayer_1x_packed.frag\n>> @@ -231,49 +231,8 @@ void main(void)\n>>  \t/* Apply AWB gains, and saturate each channel at sensor range */\n>>  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n>>  \n>> -\t/*\n>> -\t *   CCM is a 3x3 in the format\n>> -\t *\n>> -\t *   +--------------+----------------+---------------+\n>> -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n>> -\t *   +--------------+----------------+---------------+\n>> -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n>> -\t *   +--------------+----------------+---------------+\n>> -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n>> -\t *   +--------------+----------------+---------------+\n>> -\t *\n>> -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n>> -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n>> -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n>> -\t *\n>> -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n>> -\t *\n>> -\t *   CPU\n>> -\t *   float ccm [] = {\n>> -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n>> -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n>> -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n>> -\t *   };\n>> -\t *\n>> -\t *   GPU\n>> -\t *   ccm = {\n>> -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n>> -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n>> -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n>> -\t *   }\n>> -\t *\n>> -\t *   However the indexing for the mat data-type is column major hence\n>> -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n>> -\t *\n>> -\t */\n>> -\tfloat rin, gin, bin;\n>> -\trin = rgb.r;\n>> -\tgin = rgb.g;\n>> -\tbin = rgb.b;\n>> -\n>> -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n>> -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n>> -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n>> +\t/* Row major Colour Correction Matrix multiplication */\n>\n> Row-major is related to how data is stored in memory. When writing\n>\n> \tccm * rgb\n>\n> that's not relevant any more. You can drop it from the comment. Same\n> below.\n>\n>> +\trgb = ccm * rgb;\n>\n> I wonder why that was open-coded. Any idea ? \n\nI think the reason was just not realising initially, when transforming\nthe code from CPU ISP, that it can be written as a matrix multiplication\ndirectly in GPU ISP.\n\n> I suppose there's no negative performance impact from this patch, as\n> the compiler should generate the same or better instructions ?\n>\n>>  \n>>  \t/*\n>>  \t * Contrast\n>> diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag\n>> index 87e4e4915fe19679943fdcc3d213a0224b89065e..52de0a7901cfac33dbc7b306f1840ec0048cd8ea 100644\n>> --- a/src/libcamera/shaders/bayer_unpacked.frag\n>> +++ b/src/libcamera/shaders/bayer_unpacked.frag\n>> @@ -134,49 +134,9 @@ void main(void) {\n>>  \t/* Apply AWB gains, and saturate each channel at sensor range */\n>>  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n>>  \n>> -\t/*\n>> -\t *   CCM is a 3x3 in the format\n>> -\t *\n>> -\t *   +--------------+----------------+---------------+\n>> -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n>> -\t *   +--------------+----------------+---------------+\n>> -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n>> -\t *   +--------------+----------------+---------------+\n>> -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n>> -\t *   +--------------+----------------+---------------+\n>> -\t *\n>> -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n>> -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n>> -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n>> -\t *\n>> -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n>> -\t *\n>> -\t *   CPU\n>> -\t *   float ccm [] = {\n>> -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n>> -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n>> -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n>> -\t *   };\n>> -\t *\n>> -\t *   GPU\n>> -\t *   ccm = {\n>> -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n>> -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n>> -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n>> -\t *   }\n>> -\t *\n>> -\t *   However the indexing for the mat data-type is column major hence\n>> -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n>> -\t *\n>> -\t */\n>> -\tfloat rin, gin, bin;\n>> -\trin = rgb.r;\n>> -\tgin = rgb.g;\n>> -\tbin = rgb.b;\n>>  \n>> -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n>> -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n>> -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n>> +\t/* Row major Colour Correction Matrix multiplication */\n>> +\trgb = ccm * rgb;\n>>  \n>>  \t/*\n>>  \t * Contrast\n>> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n>> index 738036e649224f370bdf9a0cc59b399f8b1066de..1022f595cc71751cd0c9133b3e5755f591224dc4 100644\n>> --- a/src/libcamera/software_isp/debayer_egl.cpp\n>> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n>> @@ -464,15 +464,9 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>>  \t\t\t    << \" textureUniformProjMatrix_ \" << textureUniformProjMatrix_;\n>>  \n>>  \tGLfloat ccm[9] = {\n>> -\t\tparams.combinedMatrix[0][0],\n>> -\t\tparams.combinedMatrix[0][1],\n>> -\t\tparams.combinedMatrix[0][2],\n>> -\t\tparams.combinedMatrix[1][0],\n>> -\t\tparams.combinedMatrix[1][1],\n>> -\t\tparams.combinedMatrix[1][2],\n>> -\t\tparams.combinedMatrix[2][0],\n>> -\t\tparams.combinedMatrix[2][1],\n>> -\t\tparams.combinedMatrix[2][2],\n>> +\t\tparams.combinedMatrix[0][0], params.combinedMatrix[1][0], params.combinedMatrix[2][0],\n>> +\t\tparams.combinedMatrix[0][1], params.combinedMatrix[1][1], params.combinedMatrix[2][1],\n>> +\t\tparams.combinedMatrix[0][2], params.combinedMatrix[1][2], params.combinedMatrix[2][2],\n>\n> You're now storing the data in column-major order, ...\n>\n>>  \t};\n>>  \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);\n>\n> ... and the third argument matches that. As the libcamera Matrix class\n> stores elements in row-major order, I think it would be clearer to store\n> the data in row-major order in the ccm array as well, and set the third\n> argument to GL_TRUE accordingly.\n>\n> We could then possibly avoid copying the data to a local array (here or\n> as a separate patch).\n>\n>>  \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" <<\n>> params.combinedMatrix;\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 A3A33C32BB\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  8 Apr 2026 11:48:14 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DB78462DD4;\n\tWed,  8 Apr 2026 13:48:13 +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 03CB662CE6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  8 Apr 2026 13:48:11 +0200 (CEST)","from mail-wm1-f70.google.com (mail-wm1-f70.google.com\n\t[209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-101-Q1E-4NY9OIO47CEHVHfUbQ-1; Wed, 08 Apr 2026 07:48:09 -0400","by mail-wm1-f70.google.com with SMTP id\n\t5b1f17b1804b1-48887ff8b73so34450415e9.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 08 Apr 2026 04:48:09 -0700 (PDT)","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-4888a7165aasm639104175e9.14.2026.04.08.04.48.05\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 08 Apr 2026 04:48:06 -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=\"SeiDAfH2\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1775648890;\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=00hWNW9AFUtUmysbhVOisC2av93UlHEKbnf1yentEx0=;\n\tb=SeiDAfH2PM+S3yei6mrlXeEwbhwiWW9y43Z05AtzntdlSvH7zKZMGVvJrNNAKTiDYIc8ez\n\tvj5XduAWyjMmVo5UrK+4VLbG/9/D0BZS/fJvYblmV6+6j2IMsEBog2nuCJ0jj4IZ9BGeMS\n\tBf/D2gRqmA0bWacTAq0ywOrJ0gWYeno=","X-MC-Unique":"Q1E-4NY9OIO47CEHVHfUbQ-1","X-Mimecast-MFC-AGG-ID":"Q1E-4NY9OIO47CEHVHfUbQ_1775648888","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1775648888; x=1776253688;\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=00hWNW9AFUtUmysbhVOisC2av93UlHEKbnf1yentEx0=;\n\tb=fYK6yEtU9+RTFfV1WB2rigIYxHJ9Qm+9YXlcLBr1XlieYNON02Kq5m78xK+q/qX/Kl\n\t9Ykb+AvFwFmJ9u0MZ7qGb+tpT8pL3wZzWFH1XDQrwCzdY7qZniqhMIyPgAd65ZBZbuh6\n\tkOh4AIXnC9MHxvVWZY0usdLFw2FGqruJNakSPKlNwPRNdw46J22bnmwtxfb2489H/Pg/\n\tMjaRxUIgfWGw0QQAKEg6L9eUT4cJ++PJ5OBFaKLyepUfmqsj8M2f2GXKDg3N84Qhj8Ya\n\tf7maHfTU+mf+O//dkt3vJYnyaKnsHcUje94NZq9s43HIkqUNNnRsOX8Bqbz6XRk2BxjL\n\tIc4g==","X-Forwarded-Encrypted":"i=1;\n\tAJvYcCU/8yg6gLSY3IJ/dipD2+Iu8MCZQLoJxPa0gVrvjF0yUyGGoICCXkqDXsEFNZov70o8lqCrOfzUpJEpNsI95NI=@lists.libcamera.org","X-Gm-Message-State":"AOJu0Ywx6dvnVDrIDqTuY2GFXBH06QLXkK03Q+Qj7MFvU7LVjwFRV/e+\n\tkBM796ah/0DrOsBVwOE3V5gcSQzFF8g2c6kyhsVvXm1w95ZhE92ckA3m2ctftTurFmcu0mIpt22\n\tzZEXBxFqrikJb1XjA1nhWFpVaoBWmHHtoDB8gWxNDxFMAU1A9tpaahPVfLZl3SvbKNfSlaU68W+\n\tnQ9KZ2Lt0Vc4uw7+n6EO5Bm+4JHrtESZ2Ogaa2Q4q+vaoewy82S8P9s/01vuU=","X-Gm-Gg":"AeBDietXzPY4qnx6LVWlgGhS9obGZ8g0oU3kHLjGAjPk2L5IAXuGgh1zkmeoyDdNY6I\n\tMSknXhHoEscW3fBDgqxd8pvzs94z3n2/0BwLEG4DxlfABFbgmRDKcfZezUmv4wv2IEODXpn6JCg\n\tJ93pvjRx7K7rWdyb2sO9lELysBTXiemeH4Y9iZCuFuAjVSrWS0fYqdqV/ZUjUb4uOT7mybEm3dC\n\tdsA/UaH4UpDdeUJOWgnw2teMoo1NJ8vrtQFibEyYNjQCX2fPU3qpzWKTlMryRnikSGmiMdG9nst\n\tuixi8uURnTKonK+JIIC9R1uewu7M0LrEoy0mkSEMQi6BWvQ1gYIRU20xKmCuVpXUpNztI0iOzT9\n\tVR+hoAP4RoIc9bnjbq6rmmdGh0RhL1hqcdR9E087vLJg+sZ4NnANpyi+slA2VgsTsvsYRM6aUtT\n\tg=","X-Received":["by 2002:a05:600c:1d1c:b0:488:936a:6220 with SMTP id\n\t5b1f17b1804b1-488997d0012mr276672955e9.21.1775648887800; \n\tWed, 08 Apr 2026 04:48:07 -0700 (PDT)","by 2002:a05:600c:1d1c:b0:488:936a:6220 with SMTP id\n\t5b1f17b1804b1-488997d0012mr276672555e9.21.1775648887186; \n\tWed, 08 Apr 2026 04:48:07 -0700 (PDT)"],"From":"Milan Zamazal <mzamazal@redhat.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","In-Reply-To":"<20260408001702.GN1268443@killaraus.ideasonboard.com> (Laurent\n\tPinchart's message of \"Wed, 8 Apr 2026 03:17:02 +0300\")","References":"<20260407-kbingham-awb-split-v1-0-a39af3f4dc20@ideasonboard.com>\n\t<20260407-kbingham-awb-split-v1-5-a39af3f4dc20@ideasonboard.com>\n\t<20260408001702.GN1268443@killaraus.ideasonboard.com>","Date":"Wed, 08 Apr 2026 13:48:05 +0200","Message-ID":"<85mrzdbrm2.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":"YuX4Vzcp3EZaYERr3o-6bZiqpdaGzKBzo3O2-dpVyY8_1775648888","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":38536,"web_url":"https://patchwork.libcamera.org/comment/38536/","msgid":"<85cy09bqld.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-04-08T12:10:06","subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Kieran Bingham <kieran.bingham@ideasonboard.com> writes:\n\n> Remove the open coded matrix multiplication as glsl can perform this\n> directly. Adapt the uniform ccmUniformDataIn_ to ensure we correctly\n> upload the matrix in row major ordering.\n>\n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> ---\n>  src/libcamera/shaders/bayer_1x_packed.frag | 45 ++----------------------------\n>  src/libcamera/shaders/bayer_unpacked.frag  | 44 ++---------------------------\n>  src/libcamera/software_isp/debayer_egl.cpp | 12 ++------\n>  3 files changed, 7 insertions(+), 94 deletions(-)\n>\n> diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag\n> index 9a1992e219dd066945b3f46ec509f47a31590385..57f0be9b264bdbdf523291dc9b35ab5fd6c9ef6a 100644\n> --- a/src/libcamera/shaders/bayer_1x_packed.frag\n> +++ b/src/libcamera/shaders/bayer_1x_packed.frag\n> @@ -231,49 +231,8 @@ void main(void)\n>  \t/* Apply AWB gains, and saturate each channel at sensor range */\n>  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n>  \n> -\t/*\n> -\t *   CCM is a 3x3 in the format\n> -\t *\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> -\t *   +--------------+----------------+---------------+\n> -\t *\n> -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> -\t *\n> -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> -\t *\n> -\t *   CPU\n> -\t *   float ccm [] = {\n> -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> -\t *   };\n> -\t *\n> -\t *   GPU\n> -\t *   ccm = {\n> -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> -\t *   }\n> -\t *\n> -\t *   However the indexing for the mat data-type is column major hence\n> -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> -\t *\n> -\t */\n> -\tfloat rin, gin, bin;\n> -\trin = rgb.r;\n> -\tgin = rgb.g;\n> -\tbin = rgb.b;\n> -\n> -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> +\t/* Row major Colour Correction Matrix multiplication */\n> +\trgb = ccm * rgb;\n>  \n>  \t/*\n>  \t * Contrast\n> diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag\n> index 87e4e4915fe19679943fdcc3d213a0224b89065e..52de0a7901cfac33dbc7b306f1840ec0048cd8ea 100644\n> --- a/src/libcamera/shaders/bayer_unpacked.frag\n> +++ b/src/libcamera/shaders/bayer_unpacked.frag\n> @@ -134,49 +134,9 @@ void main(void) {\n>  \t/* Apply AWB gains, and saturate each channel at sensor range */\n>  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n>  \n> -\t/*\n> -\t *   CCM is a 3x3 in the format\n> -\t *\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> -\t *   +--------------+----------------+---------------+\n> -\t *\n> -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> -\t *\n> -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> -\t *\n> -\t *   CPU\n> -\t *   float ccm [] = {\n> -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> -\t *   };\n> -\t *\n> -\t *   GPU\n> -\t *   ccm = {\n> -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> -\t *   }\n> -\t *\n> -\t *   However the indexing for the mat data-type is column major hence\n> -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> -\t *\n> -\t */\n> -\tfloat rin, gin, bin;\n> -\trin = rgb.r;\n> -\tgin = rgb.g;\n> -\tbin = rgb.b;\n>  \n> -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> +\t/* Row major Colour Correction Matrix multiplication */\n> +\trgb = ccm * rgb;\n>  \n>  \t/*\n>  \t * Contrast\n> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> index 738036e649224f370bdf9a0cc59b399f8b1066de..1022f595cc71751cd0c9133b3e5755f591224dc4 100644\n> --- a/src/libcamera/software_isp/debayer_egl.cpp\n> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> @@ -464,15 +464,9 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>  \t\t\t    << \" textureUniformProjMatrix_ \" << textureUniformProjMatrix_;\n>  \n>  \tGLfloat ccm[9] = {\n> -\t\tparams.combinedMatrix[0][0],\n> -\t\tparams.combinedMatrix[0][1],\n> -\t\tparams.combinedMatrix[0][2],\n> -\t\tparams.combinedMatrix[1][0],\n> -\t\tparams.combinedMatrix[1][1],\n> -\t\tparams.combinedMatrix[1][2],\n> -\t\tparams.combinedMatrix[2][0],\n> -\t\tparams.combinedMatrix[2][1],\n> -\t\tparams.combinedMatrix[2][2],\n> +\t\tparams.combinedMatrix[0][0], params.combinedMatrix[1][0], params.combinedMatrix[2][0],\n> +\t\tparams.combinedMatrix[0][1], params.combinedMatrix[1][1], params.combinedMatrix[2][1],\n> +\t\tparams.combinedMatrix[0][2], params.combinedMatrix[1][2], params.combinedMatrix[2][2],\n\nThis gets reformatted to one element per line by the autoformatter.  It\ncan be prevented by wrapping the block by\n\n  /* clang-format off */\n  ...\n  /* clang-format on */\n\nOr perhaps even better by changing the element order as Laurent suggests\nand then doing something like\n\n  GLfloat ccm[9];\n  std::copy(params.combinedMatrix.data().begin(), params.combinedMatrix.data().end(), ccm);\n\n>  \t};\n>  \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);\n>  \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;","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 23109BEFBE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  8 Apr 2026 12:10:15 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6F0B262DDA;\n\tWed,  8 Apr 2026 14:10:14 +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 61A6E62CE6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  8 Apr 2026 14:10:13 +0200 (CEST)","from mail-wm1-f71.google.com (mail-wm1-f71.google.com\n\t[209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-633-GihTvUJENrKNfD_kggRpIw-1; Wed, 08 Apr 2026 08:10:11 -0400","by mail-wm1-f71.google.com with SMTP id\n\t5b1f17b1804b1-488ba2919b9so14444195e9.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 08 Apr 2026 05:10:11 -0700 (PDT)","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-4887e80a5e2sm633889215e9.1.2026.04.08.05.10.07\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 08 Apr 2026 05:10:07 -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=\"ErsI7+bR\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1775650212;\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=Zho4jVbJnP54WkxXaTWLU37h0LkrNbTGZHLcRqOxIdc=;\n\tb=ErsI7+bRXMNe9lQZOj/KNyFI+DFvpHPaDz8xl7w3s8QXxGFEpUl4/8N2fM/9fy5N6ZX0vL\n\tp0+oqHZU4g142rmWrYzJwteOPolyG1s8B8XC5uLrfqsw6eNvftY3XCtPbG5fECRbyCJJCl\n\tySro87I4Nando+4VJQ6+hXJUYsdpqH0=","X-MC-Unique":"GihTvUJENrKNfD_kggRpIw-1","X-Mimecast-MFC-AGG-ID":"GihTvUJENrKNfD_kggRpIw_1775650210","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1775650209; x=1776255009;\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=Zho4jVbJnP54WkxXaTWLU37h0LkrNbTGZHLcRqOxIdc=;\n\tb=DA7BKXw4hNQfhXfIG2dumBguLiVF6IFLrwLV2kcvCBBzHgwdH/V/LxciuR70925pxc\n\tOp7GllV629nJvN+RgUuPkHLjQMKVe3llkh/ovalxklVV1Abe+oIEzGmEv+Tlr+K6Us4T\n\togD2FjISir9345Q4Acg/HhVS9zl4IYY4dJa1s9nLwa5tq12FJi7Oye6xcaKuKozmtCD3\n\t7uKcn25PkJ/cYZtBW0T2o5X+EJcKGZEcWnB+URI6gXAbk+vlz5PMdZAXcTQuc3t5t8UL\n\tzAKef7NbrWtrOao+so5lXehdmSoKrOWl6nwvPDe22R1E5tEKBIFhXvQWhRR12qpTu1Ne\n\t7qpA==","X-Gm-Message-State":"AOJu0YyZXtQNGWmCA1Sqlv80QHIlrLIU/6ChXOX78s4kTFArgeD5F6H9\n\tTSularDJ9bwZkuo+GkEn5QiCvwsje8tQtg44ohl3Pn632XUXTqZtJvPbM9+jDroKfLZ1/pfKn0T\n\tigh7l8VFAulyGRqJBJ9YJqDKjjOKXoLya6QwugU6HQmxVebIg5cd09PzgG34NXfAH8Bu9sGZr10\n\tc+6rIVT3sFpQMB7ElOSa+fHX0qMEq83165FIw0wtGFl8WN3suHokhGwyUTE5g=","X-Gm-Gg":"AeBDievuaH6ixcfBvaQpp66b5YRCoFUFpbA0mx27qXisQS1gKVbu7TNUBd5Z97NsclS\n\tTEywstnKuSSL9QmyTGOwm1CpLTJX6klK404WpoCeh2YR1uvz6Ksi4iQ/cebuSWzRD7+qa9MWweM\n\tW5vL38oSBQwVi6jos9UNOvN9nC4Ph4O2n8bIa3f3WxIGdFJO7djxZw2MNabqZJsha0Rkt5b77ZN\n\tCcK8XHITdirkCt5ODPvl9uiEROf/3+ufmK/rAHS9VFXfsSU1MB4758iamGKVjF6YeXjaPWqedrH\n\tQ/ui2rc8MTQ4g0rizjusxh3sodCKuGItQ4526nmTEKh+/9ReXL7Ub1Yy1MBYY+my7Z0KVRc0xpx\n\tu5UJwdltwdIlOBQ7B1N9tJN0NEnh6N4kqIHBIKWVdBOpM8RIxhSvW/FT3ahrgJOdcSRJ7xwdhE9\n\t4=","X-Received":["by 2002:a05:600c:3e88:b0:488:c744:49b with SMTP id\n\t5b1f17b1804b1-488c7440750mr29010965e9.7.1775650209497; \n\tWed, 08 Apr 2026 05:10:09 -0700 (PDT)","by 2002:a05:600c:3e88:b0:488:c744:49b with SMTP id\n\t5b1f17b1804b1-488c7440750mr29010495e9.7.1775650208983; \n\tWed, 08 Apr 2026 05:10:08 -0700 (PDT)"],"From":"Milan Zamazal <mzamazal@redhat.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","In-Reply-To":"<20260407-kbingham-awb-split-v1-5-a39af3f4dc20@ideasonboard.com>\n\t(Kieran Bingham's message of \"Tue, 07 Apr 2026 23:01:08 +0100\")","References":"<20260407-kbingham-awb-split-v1-0-a39af3f4dc20@ideasonboard.com>\n\t<20260407-kbingham-awb-split-v1-5-a39af3f4dc20@ideasonboard.com>","Date":"Wed, 08 Apr 2026 14:10:06 +0200","Message-ID":"<85cy09bqld.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":"ehghU-HbRabmIp2e4f-fI2PN7fMOY2jP1TKiQopasRM_1775650210","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":38537,"web_url":"https://patchwork.libcamera.org/comment/38537/","msgid":"<20260408125124.GA1962914@killaraus.ideasonboard.com>","date":"2026-04-08T12:51:24","subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Wed, Apr 08, 2026 at 02:10:06PM +0200, Milan Zamazal wrote:\n> Kieran Bingham <kieran.bingham@ideasonboard.com> writes:\n> \n> > Remove the open coded matrix multiplication as glsl can perform this\n> > directly. Adapt the uniform ccmUniformDataIn_ to ensure we correctly\n> > upload the matrix in row major ordering.\n> >\n> > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > ---\n> >  src/libcamera/shaders/bayer_1x_packed.frag | 45 ++----------------------------\n> >  src/libcamera/shaders/bayer_unpacked.frag  | 44 ++---------------------------\n> >  src/libcamera/software_isp/debayer_egl.cpp | 12 ++------\n> >  3 files changed, 7 insertions(+), 94 deletions(-)\n> >\n> > diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag\n> > index 9a1992e219dd066945b3f46ec509f47a31590385..57f0be9b264bdbdf523291dc9b35ab5fd6c9ef6a 100644\n> > --- a/src/libcamera/shaders/bayer_1x_packed.frag\n> > +++ b/src/libcamera/shaders/bayer_1x_packed.frag\n> > @@ -231,49 +231,8 @@ void main(void)\n> >  \t/* Apply AWB gains, and saturate each channel at sensor range */\n> >  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n> >  \n> > -\t/*\n> > -\t *   CCM is a 3x3 in the format\n> > -\t *\n> > -\t *   +--------------+----------------+---------------+\n> > -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> > -\t *   +--------------+----------------+---------------+\n> > -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> > -\t *   +--------------+----------------+---------------+\n> > -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> > -\t *   +--------------+----------------+---------------+\n> > -\t *\n> > -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> > -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> > -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> > -\t *\n> > -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> > -\t *\n> > -\t *   CPU\n> > -\t *   float ccm [] = {\n> > -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> > -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> > -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> > -\t *   };\n> > -\t *\n> > -\t *   GPU\n> > -\t *   ccm = {\n> > -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> > -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> > -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> > -\t *   }\n> > -\t *\n> > -\t *   However the indexing for the mat data-type is column major hence\n> > -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> > -\t *\n> > -\t */\n> > -\tfloat rin, gin, bin;\n> > -\trin = rgb.r;\n> > -\tgin = rgb.g;\n> > -\tbin = rgb.b;\n> > -\n> > -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> > -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> > -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> > +\t/* Row major Colour Correction Matrix multiplication */\n> > +\trgb = ccm * rgb;\n> >  \n> >  \t/*\n> >  \t * Contrast\n> > diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag\n> > index 87e4e4915fe19679943fdcc3d213a0224b89065e..52de0a7901cfac33dbc7b306f1840ec0048cd8ea 100644\n> > --- a/src/libcamera/shaders/bayer_unpacked.frag\n> > +++ b/src/libcamera/shaders/bayer_unpacked.frag\n> > @@ -134,49 +134,9 @@ void main(void) {\n> >  \t/* Apply AWB gains, and saturate each channel at sensor range */\n> >  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n> >  \n> > -\t/*\n> > -\t *   CCM is a 3x3 in the format\n> > -\t *\n> > -\t *   +--------------+----------------+---------------+\n> > -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> > -\t *   +--------------+----------------+---------------+\n> > -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> > -\t *   +--------------+----------------+---------------+\n> > -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> > -\t *   +--------------+----------------+---------------+\n> > -\t *\n> > -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> > -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> > -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> > -\t *\n> > -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> > -\t *\n> > -\t *   CPU\n> > -\t *   float ccm [] = {\n> > -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> > -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> > -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> > -\t *   };\n> > -\t *\n> > -\t *   GPU\n> > -\t *   ccm = {\n> > -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> > -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> > -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> > -\t *   }\n> > -\t *\n> > -\t *   However the indexing for the mat data-type is column major hence\n> > -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> > -\t *\n> > -\t */\n> > -\tfloat rin, gin, bin;\n> > -\trin = rgb.r;\n> > -\tgin = rgb.g;\n> > -\tbin = rgb.b;\n> >  \n> > -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> > -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> > -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> > +\t/* Row major Colour Correction Matrix multiplication */\n> > +\trgb = ccm * rgb;\n> >  \n> >  \t/*\n> >  \t * Contrast\n> > diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> > index 738036e649224f370bdf9a0cc59b399f8b1066de..1022f595cc71751cd0c9133b3e5755f591224dc4 100644\n> > --- a/src/libcamera/software_isp/debayer_egl.cpp\n> > +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> > @@ -464,15 +464,9 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n> >  \t\t\t    << \" textureUniformProjMatrix_ \" << textureUniformProjMatrix_;\n> >  \n> >  \tGLfloat ccm[9] = {\n> > -\t\tparams.combinedMatrix[0][0],\n> > -\t\tparams.combinedMatrix[0][1],\n> > -\t\tparams.combinedMatrix[0][2],\n> > -\t\tparams.combinedMatrix[1][0],\n> > -\t\tparams.combinedMatrix[1][1],\n> > -\t\tparams.combinedMatrix[1][2],\n> > -\t\tparams.combinedMatrix[2][0],\n> > -\t\tparams.combinedMatrix[2][1],\n> > -\t\tparams.combinedMatrix[2][2],\n> > +\t\tparams.combinedMatrix[0][0], params.combinedMatrix[1][0], params.combinedMatrix[2][0],\n> > +\t\tparams.combinedMatrix[0][1], params.combinedMatrix[1][1], params.combinedMatrix[2][1],\n> > +\t\tparams.combinedMatrix[0][2], params.combinedMatrix[1][2], params.combinedMatrix[2][2],\n> \n> This gets reformatted to one element per line by the autoformatter.  It\n> can be prevented by wrapping the block by\n> \n>   /* clang-format off */\n>   ...\n>   /* clang-format on */\n> \n> Or perhaps even better by changing the element order as Laurent suggests\n> and then doing something like\n> \n>   GLfloat ccm[9];\n>   std::copy(params.combinedMatrix.data().begin(), params.combinedMatrix.data().end(), ccm);\n\nOr\n\n\tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_TRUE,\n\t\t\t   params.combinedMatrix.data().data());\n\nif we can assume that GLfloat is always a float.\n\n> >  \t};\n> >  \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);\n> >  \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;","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 37EB9BDCBD\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  8 Apr 2026 12:51:28 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4EACD62DDA;\n\tWed,  8 Apr 2026 14:51:27 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id EB36062CE6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  8 Apr 2026 14:51:25 +0200 (CEST)","from killaraus.ideasonboard.com\n\t(2001-14ba-703d-e500--2a1.rev.dnainternet.fi\n\t[IPv6:2001:14ba:703d:e500::2a1])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 55A1D236;\n\tWed,  8 Apr 2026 14:49:57 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"gnurUYK5\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1775652597;\n\tbh=BIspHK3Vmq3ubejK2Ljx8W3pJbIXkoLqOo83AcV02Us=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=gnurUYK5J2VGhuZHKNxBYcgaFA124b2/EuotSCBvGBKQo84eaYhQEtgBkRM5Xt64Q\n\tbj81hbSHWsfm4brIccInGuFopM4Yb+BU7yIzh1keR/gsPjqQipcliByLjIY16J3rIZ\n\tBj9OK/62cghDBsTcCkEiQcbcMHZF5jUZKY7TdeLQ=","Date":"Wed, 8 Apr 2026 15:51:24 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Milan Zamazal <mzamazal@redhat.com>","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","Message-ID":"<20260408125124.GA1962914@killaraus.ideasonboard.com>","References":"<20260407-kbingham-awb-split-v1-0-a39af3f4dc20@ideasonboard.com>\n\t<20260407-kbingham-awb-split-v1-5-a39af3f4dc20@ideasonboard.com>\n\t<85cy09bqld.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<85cy09bqld.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","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":38776,"web_url":"https://patchwork.libcamera.org/comment/38776/","msgid":"<6b531fde-c155-4c3a-a727-58ed561e1815@oss.qualcomm.com>","date":"2026-05-07T13:32:13","subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","submitter":{"id":242,"url":"https://patchwork.libcamera.org/api/people/242/","name":"Hans de Goede","email":"johannes.goede@oss.qualcomm.com"},"content":"Hi,\n\nOn 8-Apr-26 00:01, Kieran Bingham wrote:\n> Remove the open coded matrix multiplication as glsl can perform this\n> directly. Adapt the uniform ccmUniformDataIn_ to ensure we correctly\n> upload the matrix in row major ordering.\n> \n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nThanks, patch looks good to me:\n\nReviewed-by: Hans de Goede <johannes.goede@oss.qualcomm.com>\n\nRegards,\n\nHans\n\n\n\n> ---\n>  src/libcamera/shaders/bayer_1x_packed.frag | 45 ++----------------------------\n>  src/libcamera/shaders/bayer_unpacked.frag  | 44 ++---------------------------\n>  src/libcamera/software_isp/debayer_egl.cpp | 12 ++------\n>  3 files changed, 7 insertions(+), 94 deletions(-)\n> \n> diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag\n> index 9a1992e219dd066945b3f46ec509f47a31590385..57f0be9b264bdbdf523291dc9b35ab5fd6c9ef6a 100644\n> --- a/src/libcamera/shaders/bayer_1x_packed.frag\n> +++ b/src/libcamera/shaders/bayer_1x_packed.frag\n> @@ -231,49 +231,8 @@ void main(void)\n>  \t/* Apply AWB gains, and saturate each channel at sensor range */\n>  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n>  \n> -\t/*\n> -\t *   CCM is a 3x3 in the format\n> -\t *\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> -\t *   +--------------+----------------+---------------+\n> -\t *\n> -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> -\t *\n> -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> -\t *\n> -\t *   CPU\n> -\t *   float ccm [] = {\n> -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> -\t *   };\n> -\t *\n> -\t *   GPU\n> -\t *   ccm = {\n> -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> -\t *   }\n> -\t *\n> -\t *   However the indexing for the mat data-type is column major hence\n> -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> -\t *\n> -\t */\n> -\tfloat rin, gin, bin;\n> -\trin = rgb.r;\n> -\tgin = rgb.g;\n> -\tbin = rgb.b;\n> -\n> -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> +\t/* Row major Colour Correction Matrix multiplication */\n> +\trgb = ccm * rgb;\n>  \n>  \t/*\n>  \t * Contrast\n> diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag\n> index 87e4e4915fe19679943fdcc3d213a0224b89065e..52de0a7901cfac33dbc7b306f1840ec0048cd8ea 100644\n> --- a/src/libcamera/shaders/bayer_unpacked.frag\n> +++ b/src/libcamera/shaders/bayer_unpacked.frag\n> @@ -134,49 +134,9 @@ void main(void) {\n>  \t/* Apply AWB gains, and saturate each channel at sensor range */\n>  \trgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n>  \n> -\t/*\n> -\t *   CCM is a 3x3 in the format\n> -\t *\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> -\t *   +--------------+----------------+---------------+\n> -\t *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> -\t *   +--------------+----------------+---------------+\n> -\t *\n> -\t *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> -\t *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> -\t *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> -\t *\n> -\t *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> -\t *\n> -\t *   CPU\n> -\t *   float ccm [] = {\n> -\t *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> -\t *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> -\t *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> -\t *   };\n> -\t *\n> -\t *   GPU\n> -\t *   ccm = {\n> -\t *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> -\t *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> -\t *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> -\t *   }\n> -\t *\n> -\t *   However the indexing for the mat data-type is column major hence\n> -\t *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> -\t *\n> -\t */\n> -\tfloat rin, gin, bin;\n> -\trin = rgb.r;\n> -\tgin = rgb.g;\n> -\tbin = rgb.b;\n>  \n> -\trgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> -\trgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> -\trgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> +\t/* Row major Colour Correction Matrix multiplication */\n> +\trgb = ccm * rgb;\n>  \n>  \t/*\n>  \t * Contrast\n> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> index 738036e649224f370bdf9a0cc59b399f8b1066de..1022f595cc71751cd0c9133b3e5755f591224dc4 100644\n> --- a/src/libcamera/software_isp/debayer_egl.cpp\n> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> @@ -464,15 +464,9 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>  \t\t\t    << \" textureUniformProjMatrix_ \" << textureUniformProjMatrix_;\n>  \n>  \tGLfloat ccm[9] = {\n> -\t\tparams.combinedMatrix[0][0],\n> -\t\tparams.combinedMatrix[0][1],\n> -\t\tparams.combinedMatrix[0][2],\n> -\t\tparams.combinedMatrix[1][0],\n> -\t\tparams.combinedMatrix[1][1],\n> -\t\tparams.combinedMatrix[1][2],\n> -\t\tparams.combinedMatrix[2][0],\n> -\t\tparams.combinedMatrix[2][1],\n> -\t\tparams.combinedMatrix[2][2],\n> +\t\tparams.combinedMatrix[0][0], params.combinedMatrix[1][0], params.combinedMatrix[2][0],\n> +\t\tparams.combinedMatrix[0][1], params.combinedMatrix[1][1], params.combinedMatrix[2][1],\n> +\t\tparams.combinedMatrix[0][2], params.combinedMatrix[1][2], params.combinedMatrix[2][2],\n>  \t};\n>  \tglUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);\n>  \tLOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;\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 3449EBE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  7 May 2026 13:32:20 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2A66862FE1;\n\tThu,  7 May 2026 15:32:19 +0200 (CEST)","from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com\n\t[205.220.180.131])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B315962010\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  7 May 2026 15:32:17 +0200 (CEST)","from pps.filterd (m0279873.ppops.net [127.0.0.1])\n\tby mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id\n\t647AN3Y3151144 for <libcamera-devel@lists.libcamera.org>;\n\tThu, 7 May 2026 13:32:16 GMT","from mail-oi1-f199.google.com (mail-oi1-f199.google.com\n\t[209.85.167.199])\n\tby mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4e0kctt183-1\n\t(version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT)\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 07 May 2026 13:32:16 +0000 (GMT)","by mail-oi1-f199.google.com with SMTP id\n\t5614622812f47-46f083f82c7so3531555b6e.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 07 May 2026 06:32:16 -0700 (PDT)","from ?IPV6:2001:1c00:c32:7800:5bfa:a036:83f0:f9ec?\n\t(2001-1c00-0c32-7800-5bfa-a036-83f0-f9ec.cable.dynamic.v6.ziggo.nl.\n\t[2001:1c00:c32:7800:5bfa:a036:83f0:f9ec])\n\tby smtp.gmail.com with ESMTPSA id\n\ta640c23a62f3a-bc81cd34749sm83147866b.4.2026.05.07.06.32.13\n\t(version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n\tThu, 07 May 2026 06:32:14 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=qualcomm.com header.i=@qualcomm.com\n\theader.b=\"SZKq/eOR\"; dkim=pass (2048-bit key;\n\tunprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com\n\theader.b=\"gQu2ahzq\"; dkim-atps=neutral","DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h=\n\tcontent-transfer-encoding:content-type:date:from:in-reply-to\n\t:message-id:mime-version:references:subject:to; s=qcppdkim1; bh=\n\tKjHhQmqYodKAfZZFizbPvy7UskxWuVZTPjO1WwvVlCo=; b=SZKq/eOR3uWKtBAB\n\tu1jkJmsQxaOrY5lhOvlj+UcFr63SABPlg+gDSOFNhoiSp+98xrS77lShgKYgJ4MO\n\tfrUDpIqq4BCLd0A4hro1JPJ8W+dT0UivfZMzFF4KLJPz3Qsq9jxgk4valW+k6hnb\n\tjCDymUrWPRI9rLnUVdj5VHVU1fhKgyv6AZT63uDoCpCkChRHrp6h13s2GUNtxgQO\n\tdHP81XOvdhLWvi3aL8yKrK5a5oNd1189oiSrubRUVIZ+v/h3IohfP9uhBWL0i1Zx\n\txxvhe+ScKlpaGD/4ekNx11VHw6xzRb0sF2fYxAGzzinpKhIArmk4vJyiuDTShSYj\n\tvl2Irw==","v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=oss.qualcomm.com; s=google; t=1778160736; x=1778765536;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:in-reply-to:content-language:references\n\t:to:subject:from:user-agent:mime-version:date:message-id:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=KjHhQmqYodKAfZZFizbPvy7UskxWuVZTPjO1WwvVlCo=;\n\tb=gQu2ahzqIDokLtR5a6JDhNGcXGWw5mrz973GPF0jR0BVIehoXUsW1HQWbeNDDgujJW\n\t0RbPsTj8wiiFuTdXhAVkY/NyJowBlGPdPnF5hoSEWCuP1GH17Hco8sq6sqBoZm15P79t\n\tMV9pwfCJHirJaBwM4vQUu6MamcYVTkkAqOiHVkeH7fH7YLS5Ykv1uM3LIeESx9ow3EZv\n\tLVYK/xZ6OcX5Ae5PVStavx4o6JDN95+WojjoJh5CmVKyohPgFC3QiefdPA/3Lm8Ki9vC\n\tIdQwk498w8yZe3pA8K4XzW7SbfD1ccuVAIMb0zeNlKKJvQ/SXIrF303GfF5LawmoeI/L\n\tQ+uA=="],"X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1778160736; x=1778765536;\n\th=content-transfer-encoding:in-reply-to:content-language:references\n\t:to:subject:from:user-agent:mime-version:date:message-id:x-gm-gg\n\t:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;\n\tbh=KjHhQmqYodKAfZZFizbPvy7UskxWuVZTPjO1WwvVlCo=;\n\tb=gmUtJSve5uCf+X+QJ64CjlJ+OwbwmDeclHdXkrG7pcCZodJkYiOuK/ZE+YHt1/XXpQ\n\t5NJAJfF6VThVM5SKPPggNwmFnDVOAn4ICSks71ZsaEe9DgT+JxBgAQ15wl0xq3GBVHNg\n\tUd3W8076CXiTag7Qa7Z27UbbHOMl+vYOhyuQRtpKtKHR5IXkwBxYiwfTNe/5UUtejEsW\n\t1qv6peX7o/2cJ5NVmAq7MNcSUUQR5ZOnHJHKzNm03R07pG9tiqTQG/791vzbfC299Kmd\n\t9fsTlDDTkSMwyOaui3TRZC/l6+eBanq/pgP1kDVMB+DLhrRdm+dcIarZOeJl+jy6sy6Q\n\tIkvw==","X-Forwarded-Encrypted":"i=1;\n\tAFNElJ/gXXlKCE6qh8nX+p7705ftuaym053QNOz+OO1gQL6yHdAMvnphMjCyuT5a5eejVuvqpZqa/BbgDXXCCul4roU=@lists.libcamera.org","X-Gm-Message-State":"AOJu0YxDQmAxP8vBB/A/Wsaa/sxOAPUdWGnqsQ2JZE/mBzMXstzxAHox\n\tyW05Mh1gt5HWZcvuf0OpL7og3Xk4YZEv6x9pU1tF19QA65e4eS9psp/swPVaXNp4GDjqUSvFpdm\n\tMdgFBdpans6zfE1TL9h4qyWcyu1N+PeqOdtKsT/qcNtfnxSnWEenGlvyBxQg9q8BmjmQuWcPZm5\n\t2g","X-Gm-Gg":"AeBDievHDCCFSQAXvV6+cPk7Dn1uTPCK/fJTkmsbZZTSh80hOkD4B5vWmWLLmO5g1Or\n\tJ5Wl9QwybxnAWU+2M0HWV3G5ZAmfFWM6D27SlLBW72swrqEYW4sxxvJGt8ISYslhDLafpk15hik\n\tBscl6BivdwTz0k71zogv8ZHgqPbfj19rfokw/BOCYo/h653wNFl9Y5OoWp8guby+RgAtxyWYv0H\n\t4K4kk9Od3oxfMlPG6oGoyNny8kvH9lshjLkcOl6c38ulYqHs5mVhDwjOkUjh16BXlVcWZ83MD17\n\t4KHNc+oO1KVeOuE/9R28wNkhE0cW7rIP0/HD+LdWD0hi9VwVdPcLw56Iqw1a6rJP5DtiGG3okGR\n\tGFxOe//LgyJlDoFrGkluTjLtR6V3U03NcA191gMQWD4Er5/Glvn3fXU9Gr7zMLiU+3oVHCV+Qog\n\tSluMe7PcvjoSiodJgo66bVsspOwzFm42c0GGFhcQM8ReyqMTskTtIfihqjq7T2ZuTqgyHtZiaXd\n\tVXFox88RrS1onioJ7BV1PV2Hus5jEzgU1Jcpw==","X-Received":["by 2002:a05:6830:160d:b0:7dc:c70:3fde with SMTP id\n\t46e09a7af769-7e1fd21b92emr1180074a34.11.1778160735668; \n\tThu, 07 May 2026 06:32:15 -0700 (PDT)","by 2002:a05:6830:160d:b0:7dc:c70:3fde with SMTP id\n\t46e09a7af769-7e1fd21b92emr1180059a34.11.1778160735214; \n\tThu, 07 May 2026 06:32:15 -0700 (PDT)"],"Message-ID":"<6b531fde-c155-4c3a-a727-58ed561e1815@oss.qualcomm.com>","Date":"Thu, 7 May 2026 15:32:13 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","From":"johannes.goede@oss.qualcomm.com","Subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20260407-kbingham-awb-split-v1-0-a39af3f4dc20@ideasonboard.com>\n\t<20260407-kbingham-awb-split-v1-5-a39af3f4dc20@ideasonboard.com>","Content-Language":"en-US, nl","In-Reply-To":"<20260407-kbingham-awb-split-v1-5-a39af3f4dc20@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"7bit","X-Authority-Analysis":"v=2.4 cv=XsPK/1F9 c=1 sm=1 tr=0 ts=69fc9460 cx=c_pps\n\ta=yymyAM/LQ7lj/HqAiIiKTw==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10\n\ta=NGcC8JguVDcA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22\n\ta=u7WPNUs3qKkmUXheDGA7:22 a=rJkE3RaqiGZ5pbrm-msn:22 a=P1BnusSwAAAA:8\n\ta=EUspDBNiAAAA:8 a=7Q0X0yLvd0EN5QymA8kA:9 a=QEXdDO2ut3YA:10\n\ta=efpaJB4zofY2dbm2aIRb:22 a=D0XLA9XvdZm18NrgonBM:22","X-Proofpoint-GUID":"ZiC85q3lrTxg_U8Hej0e4upiof9i1MIc","X-Proofpoint-ORIG-GUID":"ZiC85q3lrTxg_U8Hej0e4upiof9i1MIc","X-Proofpoint-Spam-Details-Enc":"AW1haW4tMjYwNTA3MDEzNSBTYWx0ZWRfXzZK8KUvvifbD\n\tmeXiJO5uLJPjMUKYA9KD42knUD4gIvTYiIQe9BRCCTR401RdP6SVhcmWnT1sA5oTD0v1cZGZ9xN\n\tN9NJ4ONPgjT6QR53SrCHkGuOX6w2cEhiZvnl8s2wSai71PlY34dGHqx252Z76m+QSdrrV42cXG0\n\tnkHJW7Ne3AI3ZiKIamaYnesdBE/N0mDMed/kNymS3nIzdYuoa41k5i77vl27dtflH8N/RsekLv+\n\tWLM5JUDBPSpC6JWOvlXGlliq+P0hkPTKRxhOOyKKpGpXRicwdR+0s8ZcIUKrXQLgoEJGxaTg0jk\n\tyJ2ROKn1aiVPdixj9B3lvRLXoXswSxStIgEIBKdkA9iyEKZ5+efxJF4j0KSdU1LT8RDellikq3B\n\tx4IMKyKpS/mfewzfZUjn7NysXOArY4GbYoNMO36Bv3XNdCgNv/auvg75d8vsSSQIJKl4l3Chv3X\n\tRcMFyOJ3wUJ+ecTf90Q==","X-Proofpoint-Virus-Version":"vendor=baseguard\n\tengine=ICAP:2.0.293, Aquarius:18.0.1143, Hydra:6.1.51,\n\tFMLib:17.12.100.49\n\tdefinitions=2026-05-07_01,2026-05-06_01,2025-10-01_01","X-Proofpoint-Spam-Details":"rule=outbound_notspam policy=outbound score=0\n\tlowpriorityscore=0 impostorscore=0 adultscore=0 suspectscore=0\n\tphishscore=0\n\tpriorityscore=1501 malwarescore=0 bulkscore=0 spamscore=0\n\tclxscore=1015\n\tclassifier=typeunknown authscore=0 authtc= authcc= route=outbound\n\tadjust=0\n\treason=mlx scancount=1 engine=8.22.0-2604200000\n\tdefinitions=main-2605070135","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":38843,"web_url":"https://patchwork.libcamera.org/comment/38843/","msgid":"<177843800402.2475891.3249650102950395666@ping.linuxembedded.co.uk>","date":"2026-05-10T18:33:24","subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Laurent Pinchart (2026-04-08 13:51:24)\n> On Wed, Apr 08, 2026 at 02:10:06PM +0200, Milan Zamazal wrote:\n> > Kieran Bingham <kieran.bingham@ideasonboard.com> writes:\n> > \n> > > Remove the open coded matrix multiplication as glsl can perform this\n> > > directly. Adapt the uniform ccmUniformDataIn_ to ensure we correctly\n> > > upload the matrix in row major ordering.\n> > >\n> > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > ---\n> > >  src/libcamera/shaders/bayer_1x_packed.frag | 45 ++----------------------------\n> > >  src/libcamera/shaders/bayer_unpacked.frag  | 44 ++---------------------------\n> > >  src/libcamera/software_isp/debayer_egl.cpp | 12 ++------\n> > >  3 files changed, 7 insertions(+), 94 deletions(-)\n> > >\n> > > diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag\n> > > index 9a1992e219dd066945b3f46ec509f47a31590385..57f0be9b264bdbdf523291dc9b35ab5fd6c9ef6a 100644\n> > > --- a/src/libcamera/shaders/bayer_1x_packed.frag\n> > > +++ b/src/libcamera/shaders/bayer_1x_packed.frag\n> > > @@ -231,49 +231,8 @@ void main(void)\n> > >     /* Apply AWB gains, and saturate each channel at sensor range */\n> > >     rgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n> > >  \n> > > -   /*\n> > > -    *   CCM is a 3x3 in the format\n> > > -    *\n> > > -    *   +--------------+----------------+---------------+\n> > > -    *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> > > -    *   +--------------+----------------+---------------+\n> > > -    *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> > > -    *   +--------------+----------------+---------------+\n> > > -    *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> > > -    *   +--------------+----------------+---------------+\n> > > -    *\n> > > -    *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> > > -    *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> > > -    *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> > > -    *\n> > > -    *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> > > -    *\n> > > -    *   CPU\n> > > -    *   float ccm [] = {\n> > > -    *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> > > -    *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> > > -    *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> > > -    *   };\n> > > -    *\n> > > -    *   GPU\n> > > -    *   ccm = {\n> > > -    *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> > > -    *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> > > -    *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> > > -    *   }\n> > > -    *\n> > > -    *   However the indexing for the mat data-type is column major hence\n> > > -    *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> > > -    *\n> > > -    */\n> > > -   float rin, gin, bin;\n> > > -   rin = rgb.r;\n> > > -   gin = rgb.g;\n> > > -   bin = rgb.b;\n> > > -\n> > > -   rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> > > -   rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> > > -   rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> > > +   /* Row major Colour Correction Matrix multiplication */\n> > > +   rgb = ccm * rgb;\n> > >  \n> > >     /*\n> > >      * Contrast\n> > > diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag\n> > > index 87e4e4915fe19679943fdcc3d213a0224b89065e..52de0a7901cfac33dbc7b306f1840ec0048cd8ea 100644\n> > > --- a/src/libcamera/shaders/bayer_unpacked.frag\n> > > +++ b/src/libcamera/shaders/bayer_unpacked.frag\n> > > @@ -134,49 +134,9 @@ void main(void) {\n> > >     /* Apply AWB gains, and saturate each channel at sensor range */\n> > >     rgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);\n> > >  \n> > > -   /*\n> > > -    *   CCM is a 3x3 in the format\n> > > -    *\n> > > -    *   +--------------+----------------+---------------+\n> > > -    *   | RedRedGain   | RedGreenGain   | RedBlueGain   |\n> > > -    *   +--------------+----------------+---------------+\n> > > -    *   | GreenRedGain | GreenGreenGain | GreenBlueGain |\n> > > -    *   +--------------+----------------+---------------+\n> > > -    *   | BlueRedGain  |  BlueGreenGain | BlueBlueGain  |\n> > > -    *   +--------------+----------------+---------------+\n> > > -    *\n> > > -    *   Rout = RedRedGain * Rin + RedGreenGain * Gin + RedBlueGain * Bin\n> > > -    *   Gout = GreenRedGain * Rin + GreenGreenGain * Gin + GreenBlueGain * Bin\n> > > -    *   Bout = BlueRedGain * Rin + BlueGreenGain * Gin + BlueBlueGain * Bin\n> > > -    *\n> > > -    *   We upload to the GPU without transposition glUniformMatrix3f(.., .., GL_FALSE, ccm);\n> > > -    *\n> > > -    *   CPU\n> > > -    *   float ccm [] = {\n> > > -    *             RedRedGain,   RedGreenGain,   RedBlueGain,\n> > > -    *             GreenRedGain, GreenGreenGain, GreenBlueGain,\n> > > -    *             BlueRedGain,  BlueGreenGain,  BlueBlueGain,\n> > > -    *   };\n> > > -    *\n> > > -    *   GPU\n> > > -    *   ccm = {\n> > > -    *             RedRedGain,   GreenRedGain,   BlueRedGain,\n> > > -    *             RedGreenGain, GreenGreenGain, BlueGreenGain,\n> > > -    *             RedBlueGain,  GreenBlueGain,  BlueBlueGain,\n> > > -    *   }\n> > > -    *\n> > > -    *   However the indexing for the mat data-type is column major hence\n> > > -    *   ccm[0][0] = RedRedGain, ccm[0][1] = RedGreenGain, ccm[0][2] = RedBlueGain\n> > > -    *\n> > > -    */\n> > > -   float rin, gin, bin;\n> > > -   rin = rgb.r;\n> > > -   gin = rgb.g;\n> > > -   bin = rgb.b;\n> > >  \n> > > -   rgb.r = (rin * ccm[0][0]) + (gin * ccm[0][1]) + (bin * ccm[0][2]);\n> > > -   rgb.g = (rin * ccm[1][0]) + (gin * ccm[1][1]) + (bin * ccm[1][2]);\n> > > -   rgb.b = (rin * ccm[2][0]) + (gin * ccm[2][1]) + (bin * ccm[2][2]);\n> > > +   /* Row major Colour Correction Matrix multiplication */\n> > > +   rgb = ccm * rgb;\n> > >  \n> > >     /*\n> > >      * Contrast\n> > > diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> > > index 738036e649224f370bdf9a0cc59b399f8b1066de..1022f595cc71751cd0c9133b3e5755f591224dc4 100644\n> > > --- a/src/libcamera/software_isp/debayer_egl.cpp\n> > > +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> > > @@ -464,15 +464,9 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n> > >                         << \" textureUniformProjMatrix_ \" << textureUniformProjMatrix_;\n> > >  \n> > >     GLfloat ccm[9] = {\n> > > -           params.combinedMatrix[0][0],\n> > > -           params.combinedMatrix[0][1],\n> > > -           params.combinedMatrix[0][2],\n> > > -           params.combinedMatrix[1][0],\n> > > -           params.combinedMatrix[1][1],\n> > > -           params.combinedMatrix[1][2],\n> > > -           params.combinedMatrix[2][0],\n> > > -           params.combinedMatrix[2][1],\n> > > -           params.combinedMatrix[2][2],\n> > > +           params.combinedMatrix[0][0], params.combinedMatrix[1][0], params.combinedMatrix[2][0],\n> > > +           params.combinedMatrix[0][1], params.combinedMatrix[1][1], params.combinedMatrix[2][1],\n> > > +           params.combinedMatrix[0][2], params.combinedMatrix[1][2], params.combinedMatrix[2][2],\n> > \n> > This gets reformatted to one element per line by the autoformatter.  It\n> > can be prevented by wrapping the block by\n> > \n> >   /* clang-format off */\n> >   ...\n> >   /* clang-format on */\n> > \n> > Or perhaps even better by changing the element order as Laurent suggests\n> > and then doing something like\n> > \n> >   GLfloat ccm[9];\n> >   std::copy(params.combinedMatrix.data().begin(), params.combinedMatrix.data().end(), ccm);\n> \n> Or\n> \n>         glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_TRUE,\n>                            params.combinedMatrix.data().data());\n\nThis works in my tests, so that's the solution I'm using to simplify all\nthis.\n\n--\nKieran\n\n\n> \n> if we can assume that GLfloat is always a float.\n> \n> > >     };\n> > >     glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);\n> > >     LOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;\n> \n> -- \n> Regards,\n> \n> Laurent Pinchart","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 844CEBDCBD\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 10 May 2026 18:33:29 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5D46663020;\n\tSun, 10 May 2026 20:33:28 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DED1762E6A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 10 May 2026 20:33:26 +0200 (CEST)","from monstersaurus.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 5ABFC18BC;\n\tSun, 10 May 2026 20:33:20 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"OD5EGtov\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1778438000;\n\tbh=jFj6SJnGRZ9rY+ALIGo9Rwuq704R3bvm3DnDxjL6ewg=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=OD5EGtovsUJec45tzmUf4tTE7xB637dvPBLtpiywHykV8/9I80Sgzpyy4AwdTbNnM\n\t5ricoB/tJNdNrbt8utst8MeHyEl/2mGcPX6ySnCe4kbNJPgFv3gxH9Aoe41lUh0hta\n\tfEeXv5XTOKu0wgLRQP46Xd1yvLpqMJM8lBD6aCI0=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20260408125124.GA1962914@killaraus.ideasonboard.com>","References":"<20260407-kbingham-awb-split-v1-0-a39af3f4dc20@ideasonboard.com>\n\t<20260407-kbingham-awb-split-v1-5-a39af3f4dc20@ideasonboard.com>\n\t<85cy09bqld.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>\n\t<20260408125124.GA1962914@killaraus.ideasonboard.com>","Subject":"Re: [PATCH 05/13] shaders: bayer: Use native matrix multiplication","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tMilan Zamazal <mzamazal@redhat.com>","Date":"Sun, 10 May 2026 19:33:24 +0100","Message-ID":"<177843800402.2475891.3249650102950395666@ping.linuxembedded.co.uk>","User-Agent":"alot/0.9.1","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>"}}]