[{"id":38948,"web_url":"https://patchwork.libcamera.org/comment/38948/","msgid":"<855x4a8jza.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-05-26T11:54:01","subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Hi,\n\nthank you for the patch.\n\nJai Luthra <jai.luthra@ideasonboard.com> writes:\n\n> Add support for debayering 12-bit CSI2 packed raw bayer formats.\n>\n> Also add support for the same in SwStats, skipping one 2x2 block\n> horizontally and skipping every 3rd and 4th line vertically, like done\n> for other raw bayer formats.\n>\n> GPUISP support was always present in the packed shaders (which already\n> handle skipping the pixel with LSBs), so enable it too.\n>\n> Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>\n> ---\n> This is tested for RGGB12P using IMX678 on Arduino Uno Q. The sensor\n> doesn't change bayer layout on flips, so I couldn't verify other\n> layouts.\n> ---\n>  .../libcamera/internal/software_isp/swstats_cpu.h  |   3 +\n>  src/libcamera/software_isp/debayer_cpu.cpp         | 107 +++++++++++++++++++++\n>  src/libcamera/software_isp/debayer_cpu.h           |   9 ++\n>  src/libcamera/software_isp/debayer_egl.cpp         |  13 +++\n>  src/libcamera/software_isp/swstats_cpu.cpp         |  78 +++++++++++++++\n>  5 files changed, 210 insertions(+)\n>\n> diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h\n> index b5348c6f..13fa7582 100644\n> --- a/include/libcamera/internal/software_isp/swstats_cpu.h\n> +++ b/include/libcamera/internal/software_isp/swstats_cpu.h\n> @@ -98,6 +98,9 @@ private:\n>  \t/* Bayer 10 bpp packed */\n>  \tvoid statsBGGR10PLine0(const uint8_t *src[], SwIspStats &stats);\n>  \tvoid statsGBRG10PLine0(const uint8_t *src[], SwIspStats &stats);\n> +\t/* Bayer 12 bpp packed */\n> +\tvoid statsBGGR12PLine0(const uint8_t *src[], SwIspStats &stats);\n> +\tvoid statsGBRG12PLine0(const uint8_t *src[], SwIspStats &stats);\n>  \n>  \tvoid processBayerFrame2(MappedFrameBuffer &in);\n>  \n> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n> index 1f9b24da..2751dd30 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.cpp\n> +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n> @@ -351,6 +351,78 @@ void DebayerCpu::debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[])\n>  \t}\n>  }\n>  \n> +template<bool addAlphaByte, bool ccmEnabled>\n> +void DebayerCpu::debayer12P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n> +{\n> +\tconst int widthInBytes = window_.width * 3 / 2;\n> +\tconst uint8_t *prev = src[0];\n> +\tconst uint8_t *curr = src[1];\n> +\tconst uint8_t *next = src[2];\n> +\n> +\tfor (int x = 0; x < widthInBytes;) {\n> +\t\t/* Even pixel */\n> +\t\tBGGR_BGR888(2, 1, 1)\n> +\t\t/* Odd pixel RGGB -> GRBG */\n\nBGGR -> GBRG\n\n> +\t\tGBRG_BGR888(1, 2, 1)\n> +\t\t/* Skip 3rd src byte with 2 x 4 least-significant-bits */\n> +\t\tx++;\n> +\t}\n> +}\n> +\n> +template<bool addAlphaByte, bool ccmEnabled>\n> +void DebayerCpu::debayer12P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n> +{\n> +\tconst int widthInBytes = window_.width * 3 / 2;\n> +\tconst uint8_t *prev = src[0];\n> +\tconst uint8_t *curr = src[1];\n> +\tconst uint8_t *next = src[2];\n> +\n> +\tfor (int x = 0; x < widthInBytes;) {\n> +\t\t/* Even pixel */\n> +\t\tGRBG_BGR888(2, 1, 1)\n> +\t\t/* Odd pixel RGGB -> GRBG */\n\nGRBG -> RGGB\n\n> +\t\tRGGB_BGR888(1, 2, 1)\n> +\t\t/* Skip 3rd src byte with 2 x 4 least-significant-bits */\n> +\t\tx++;\n> +\t}\n> +}\n> +\n> +template<bool addAlphaByte, bool ccmEnabled>\n> +void DebayerCpu::debayer12P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[])\n> +{\n> +\tconst int widthInBytes = window_.width * 3 / 2;\n> +\tconst uint8_t *prev = src[0];\n> +\tconst uint8_t *curr = src[1];\n> +\tconst uint8_t *next = src[2];\n> +\n> +\tfor (int x = 0; x < widthInBytes;) {\n> +\t\t/* Even pixel */\n> +\t\tGBRG_BGR888(2, 1, 1)\n> +\t\t/* Odd pixel RGGB -> GRBG */\n\nGBRG -> BGGR\n\n> +\t\tBGGR_BGR888(1, 2, 1)\n> +\t\t/* Skip 3rd src byte with 2 x 4 least-significant-bits */\n> +\t\tx++;\n> +\t}\n> +}\n> +\n> +template<bool addAlphaByte, bool ccmEnabled>\n> +void DebayerCpu::debayer12P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[])\n> +{\n> +\tconst int widthInBytes = window_.width * 3 / 2;\n> +\tconst uint8_t *prev = src[0];\n> +\tconst uint8_t *curr = src[1];\n> +\tconst uint8_t *next = src[2];\n> +\n> +\tfor (int x = 0; x < widthInBytes;) {\n> +\t\t/* Even pixel */\n> +\t\tRGGB_BGR888(2, 1, 1)\n> +\t\t/* Odd pixel RGGB -> GRBG */\n> +\t\tGRBG_BGR888(1, 2, 1)\n> +\t\t/* Skip 3rd src byte with 2 x 4 least-significant-bits */\n> +\t\tx++;\n> +\t}\n> +}\n\n(I wish we could get rid of all the duplication here one day; not in\nthis patch.)\n\n> +\n>  /*\n>   * Setup the Debayer object according to the passed in parameters.\n>   * Return 0 on success, a negative errno value on failure\n> @@ -391,6 +463,21 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf\n>  \t\treturn 0;\n>  \t}\n>  \n> +\tif (bayerFormat.bitDepth == 12 &&\n> +\t    bayerFormat.packing == BayerFormat::Packing::CSI2 &&\n> +\t    isStandardBayerOrder(bayerFormat.order)) {\n> +\t\tconfig.bpp = 12;\n> +\t\tconfig.patternSize.width = 2; /* 3 bytes per *2* pixels */\n> +\t\tconfig.patternSize.height = 2;\n> +\t\tconfig.outputFormats = std::vector<PixelFormat>({ formats::RGB888,\n> +\t\t\t\t\t\t\t\t  formats::XRGB8888,\n> +\t\t\t\t\t\t\t\t  formats::ARGB8888,\n> +\t\t\t\t\t\t\t\t  formats::BGR888,\n> +\t\t\t\t\t\t\t\t  formats::XBGR8888,\n> +\t\t\t\t\t\t\t\t  formats::ABGR8888 });\n\nThe output formats are all the same in all the cases, let's extract them\nto a common variable?\n\n> +\t\treturn 0;\n> +\t}\n> +\n>  \tLOG(Debayer, Info)\n>  \t\t<< \"Unsupported input format \" << inputFormat.toString();\n>  \treturn -EINVAL;\n> @@ -538,6 +625,26 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat,\n>  \t\t}\n>  \t}\n>  \n> +\tif (bayerFormat.bitDepth == 12 &&\n> +\t    bayerFormat.packing == BayerFormat::Packing::CSI2) {\n> +\t\tswitch (bayerFormat.order) {\n> +\t\tcase BayerFormat::BGGR:\n> +\t\t\tSET_DEBAYER_METHODS(debayer12P_BGBG_BGR888, debayer12P_GRGR_BGR888)\n> +\t\t\treturn 0;\n> +\t\tcase BayerFormat::GBRG:\n> +\t\t\tSET_DEBAYER_METHODS(debayer12P_GBGB_BGR888, debayer12P_RGRG_BGR888)\n> +\t\t\treturn 0;\n> +\t\tcase BayerFormat::GRBG:\n> +\t\t\tSET_DEBAYER_METHODS(debayer12P_GRGR_BGR888, debayer12P_BGBG_BGR888)\n> +\t\t\treturn 0;\n> +\t\tcase BayerFormat::RGGB:\n> +\t\t\tSET_DEBAYER_METHODS(debayer12P_RGRG_BGR888, debayer12P_GBGB_BGR888)\n> +\t\t\treturn 0;\n> +\t\tdefault:\n> +\t\t\tbreak;\n> +\t\t}\n> +\t}\n> +\n>  \treturn invalidFmt();\n>  }\n>  \n> diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\n> index 68da9508..5281c65c 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.h\n> +++ b/src/libcamera/software_isp/debayer_cpu.h\n> @@ -110,6 +110,15 @@ private:\n>  \tvoid debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]);\n>  \ttemplate<bool addAlphaByte, bool ccmEnabled>\n>  \tvoid debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]);\n> +\t/* CSI-2 packed 12-bit raw bayer format (all the 4 orders) */\n> +\ttemplate<bool addAlphaByte, bool ccmEnabled>\n> +\tvoid debayer12P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);\n> +\ttemplate<bool addAlphaByte, bool ccmEnabled>\n> +\tvoid debayer12P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);\n> +\ttemplate<bool addAlphaByte, bool ccmEnabled>\n> +\tvoid debayer12P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]);\n> +\ttemplate<bool addAlphaByte, bool ccmEnabled>\n> +\tvoid debayer12P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]);\n>  \n>  \tstatic int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config);\n>  \tstatic int getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config);\n> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> index eae4c57f..53adbdce 100644\n> --- a/src/libcamera/software_isp/debayer_egl.cpp\n> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> @@ -78,6 +78,19 @@ int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf\n>  \t\treturn 0;\n>  \t}\n>  \n> +\tif (bayerFormat.bitDepth == 12 &&\n> +\t    bayerFormat.packing == BayerFormat::Packing::CSI2 &&\n> +\t    isStandardBayerOrder(bayerFormat.order)) {\n> +\t\tconfig.bpp = 12;\n> +\t\tconfig.patternSize.width = 2; /* 3 bytes per *2* pixels */\n> +\t\tconfig.patternSize.height = 2;\n> +\t\tconfig.outputFormats = std::vector<PixelFormat>({ formats::XRGB8888,\n> +\t\t\t\t\t\t\t\t  formats::ARGB8888,\n> +\t\t\t\t\t\t\t\t  formats::XBGR8888,\n> +\t\t\t\t\t\t\t\t  formats::ABGR8888 });\n\nHere too.\n\n> +\t\treturn 0;\n> +\t}\n> +\n>  \tLOG(Debayer, Error)\n>  \t\t<< \"Unsupported input format \" << inputFormat;\n>  \n> diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\n> index 0815ec9a..1deee942 100644\n> --- a/src/libcamera/software_isp/swstats_cpu.cpp\n> +++ b/src/libcamera/software_isp/swstats_cpu.cpp\n> @@ -323,6 +323,58 @@ void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src[], SwIspStats &stats)\n>  \tSWSTATS_FINISH_LINE_STATS()\n>  }\n>  \n> +void SwStatsCpu::statsBGGR12PLine0(const uint8_t *src[], SwIspStats &stats)\n> +{\n> +\tconst uint8_t *src0 = src[1] + window_.x * 3 / 2;\n> +\tconst uint8_t *src1 = src[2] + window_.x * 3 / 2;\n> +\tconst unsigned int widthInBytes = window_.width * 3 / 2;\n> +\n> +\tSWSTATS_START_LINE_STATS(uint8_t)\n> +\n> +\tif (swapLines_)\n> +\t\tstd::swap(src0, src1);\n> +\n> +\t/* x += 6 sample every other 2x2 block */\n> +\tfor (unsigned int x = 0; x < widthInBytes; x += 6) {\n> +\t\tb = src0[x];\n> +\t\tg = src0[x + 1];\n> +\t\tg2 = src1[x];\n> +\t\tr = src1[x + 1];\n> +\n> +\t\tg = (g + g2) / 2;\n> +\n> +\t\tSWSTATS_ACCUMULATE_LINE_STATS(1)\n> +\t}\n> +\n> +\tSWSTATS_FINISH_LINE_STATS()\n> +}\n> +\n> +void SwStatsCpu::statsGBRG12PLine0(const uint8_t *src[], SwIspStats &stats)\n> +{\n> +\tconst uint8_t *src0 = src[1] + window_.x * 3 / 2;\n> +\tconst uint8_t *src1 = src[2] + window_.x * 3 / 2;\n> +\tconst unsigned int widthInBytes = window_.width * 3 / 2;\n> +\n> +\tSWSTATS_START_LINE_STATS(uint8_t)\n> +\n> +\tif (swapLines_)\n> +\t\tstd::swap(src0, src1);\n> +\n> +\t/* x += 6 sample every other 2x2 block */\n> +\tfor (unsigned int x = 0; x < widthInBytes; x += 6) {\n> +\t\tg = src0[x];\n> +\t\tb = src0[x + 1];\n> +\t\tr = src1[x];\n> +\t\tg2 = src1[x + 1];\n> +\n> +\t\tg = (g + g2) / 2;\n> +\n> +\t\tSWSTATS_ACCUMULATE_LINE_STATS(1)\n> +\t}\n> +\n> +\tSWSTATS_FINISH_LINE_STATS()\n> +}\n> +\n>  /**\n>   * \\brief Reset state to start statistics gathering for a new frame\n>   * \\param[in] frame The frame number\n> @@ -466,6 +518,32 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg, unsigned int stat\n>  \t\t}\n>  \t}\n>  \n> +\tif (bayerFormat.bitDepth == 12 &&\n> +\t    bayerFormat.packing == BayerFormat::Packing::CSI2) {\n> +\t\tpatternSize_.height = 2;\n> +\t\tpatternSize_.width = 2; /* 3 bytes for *2* pixels */\n> +\t\t/* Skip every 3th and 4th line, sample every other 2x2 block */\n> +\t\tySkipMask_ = 0x02;\n> +\t\txShift_ = 0;\n> +\t\tsumShift_ = 0;\n> +\t\tprocessFrame_ = &SwStatsCpu::processBayerFrame2;\n> +\n> +\t\tswitch (bayerFormat.order) {\n> +\t\tcase BayerFormat::BGGR:\n> +\t\tcase BayerFormat::GRBG:\n> +\t\t\tstats0_ = &SwStatsCpu::statsBGGR12PLine0;\n> +\t\t\tswapLines_ = bayerFormat.order == BayerFormat::GRBG;\n> +\t\t\treturn 0;\n> +\t\tcase BayerFormat::GBRG:\n> +\t\tcase BayerFormat::RGGB:\n> +\t\t\tstats0_ = &SwStatsCpu::statsGBRG12PLine0;\n> +\t\t\tswapLines_ = bayerFormat.order == BayerFormat::RGGB;\n> +\t\t\treturn 0;\n> +\t\tdefault:\n> +\t\t\tbreak;\n> +\t\t}\n> +\t}\n> +\n\nThis is almost identical to the 10-bit case, it should be worth to deduplicate.\n\n>  \tLOG(SwStatsCpu, Info)\n>  \t\t<< \"Unsupported input format \" << inputCfg.pixelFormat.toString();\n>  \treturn -EINVAL;\n>\n> ---\n> base-commit: 1f97c59d276922d387f7bfcfaa6d54b4084e43c1\n> change-id: 20260522-swisp_12p-6ad22e4d08b0\n>\n> Best regards,","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 84284BDCBC\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 26 May 2026 11:54:11 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3B45162FEC;\n\tTue, 26 May 2026 13:54:10 +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 D3F7162FB1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 May 2026 13:54:07 +0200 (CEST)","from mail-wr1-f69.google.com (mail-wr1-f69.google.com\n\t[209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-437-a7o3eyoGM-m3O4tdobj5yQ-1; Tue, 26 May 2026 07:54:05 -0400","by mail-wr1-f69.google.com with SMTP id\n\tffacd0b85a97d-44f65835b77so7643270f8f.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 May 2026 04:54:04 -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\tffacd0b85a97d-45ed1939c6asm13830978f8f.2.2026.05.26.04.54.01\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 26 May 2026 04:54:02 -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=\"JtA4wjOe\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1779796446;\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=51zXT1zacReeMPFp2jGT1Y+BRGe5xmQXQKwWBqaIRnA=;\n\tb=JtA4wjOecFOQ05ZFV1thgs+Urx86ptawRyl2cDQ+F85mIwZBxcM8GZeVUZDx/anFrpJ/Nk\n\tlBSYc+ZcNGhhqGwz/x06cF8d2+g6/1lnHadkbfZGjzIbhzQ5n66C/UTSfWwsnwNxAsbFLo\n\tretY0Du1r107LtzX9mEUpf9Y8yn3hwk=","X-MC-Unique":"a7o3eyoGM-m3O4tdobj5yQ-1","X-Mimecast-MFC-AGG-ID":"a7o3eyoGM-m3O4tdobj5yQ_1779796444","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1779796444; x=1780401244;\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=51zXT1zacReeMPFp2jGT1Y+BRGe5xmQXQKwWBqaIRnA=;\n\tb=JgbSRv+fApZOxxzUXdc5UJInVULeJvP2PegPW8pEO7xGtGTSuBd5rD4nCfhOs1KIKC\n\tnnjekBuYQ/ifaQpLvSN91W39cg/iXIm5KxiEaLq8LLgibNzh1ibUSKegS/Wa1Qsw7Uew\n\tElhVN1OMEV9wE4AFHMar6oaOsvBp8HhKzEzdwODHsBgvNfSV7F7jY/rzlC5w9p07caiV\n\tW1QrAbkL20hR7m2XTBaGdOvWHz3Av98RPa6x7kCLth0GoACtMzMZZvW92qY9ZMGtsgXI\n\tOfuWY0qermDJsNrwFhrOu5wzISowZR2tLsLdgeHv/GD0OuqMce8UryQoNxYckU4W1Fgo\n\tLlVA==","X-Forwarded-Encrypted":"i=1;\n\tAFNElJ9AbZ97R0lrFph6J7wSnbO7Uk3AGZyqiCdwMlnB6edTxCJFS/gClqCXj75QclYeltt1Ev03W1/M8jCK5bvBgNg=@lists.libcamera.org","X-Gm-Message-State":"AOJu0YyPTA+B8Nw2HgnD8uMM4QKc2XWv6CiAhv3RNM5jbdA6sS68KNLR\n\tcVJAHgJS6YDx1LGH8Uvw9heH1UYsZcgoX9MhZLzfP7kIOLqswwV17AEW8uoXuNVvlDMvWm0eTic\n\tt+Q4CCZ/fogLtG6xFeQ6XzlgFixOSmo9kHrf8DXsxsZfOVyKXH6BA2vDa36YlIXQHlivQpUauWx\n\t3IK3Cu+iyYBwtvo7+pznXCOW6/ANnsZZJywkADs8j7LGaJ/UmszwebP/WTKec=","X-Gm-Gg":"Acq92OGdj2/JgclKYX4JK8CAYZQb3G0izVwkCnigaKY7+hUxbRGsoUk7XLuiAVLc57K\n\tP61eVaZO+c0p/qrDj5Qq44WWwIsxngvTc/rroP6OZaaqJI6WUei6zkIyWc5Zk2wEkWLpX5Y07Dw\n\te4A70b0fl6CrgSvfTrFs4cZB+xxu+Lzz4EiTQvBsVHrAqv3cZI/tHQ5ZcXzCYymLQe+5rquGWn7\n\to6L3uF3dZ4Eso4rILcBVFgV2nebhtoWFlGfWcsO2smxSCXEQQ5ZFVkcg/89SS4sq0MhxDrFUYki\n\t9mGlo8zcrMu2CcMqCAm77JL6Auo7VWOqe3/OjmX+WpVTebJfl7cHhXxyFIRBxRl1gLJfG2t0YxA\n\tF3GE92C3RmWvoqs5RJqk0K4zZnPUS4dqqh9TascExyaPgz3B2tHCQcjeuFxfpOe53yx4qkeGbG1\n\tw=","X-Received":["by 2002:a05:6000:26c3:b0:43d:69ff:6898 with SMTP id\n\tffacd0b85a97d-45eb369ce77mr30575619f8f.9.1779796443821; \n\tTue, 26 May 2026 04:54:03 -0700 (PDT)","by 2002:a05:6000:26c3:b0:43d:69ff:6898 with SMTP id\n\tffacd0b85a97d-45eb369ce77mr30575545f8f.9.1779796443165; \n\tTue, 26 May 2026 04:54:03 -0700 (PDT)"],"From":"Milan Zamazal <mzamazal@redhat.com>","To":"Jai Luthra <jai.luthra@ideasonboard.com>","Cc":"Hans de Goede <johannes.goede@oss.qualcomm.com>,\n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","In-Reply-To":"<20260522-swisp_12p-v1-1-e115c35387b7@ideasonboard.com> (Jai\n\tLuthra's message of \"Fri, 22 May 2026 16:37:56 +0200\")","References":"<20260522-swisp_12p-v1-1-e115c35387b7@ideasonboard.com>","Date":"Tue, 26 May 2026 13:54:01 +0200","Message-ID":"<855x4a8jza.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":"g4kJRv9N73NLq8NKqGqq2gjTSHIwe20EH-F-4wJBw2k_1779796444","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":38956,"web_url":"https://patchwork.libcamera.org/comment/38956/","msgid":"<00f3f355-cc91-49eb-8a92-e8b3b0ac5d02@nxsw.ie>","date":"2026-05-26T17:52:36","subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","submitter":{"id":226,"url":"https://patchwork.libcamera.org/api/people/226/","name":"Bryan O'Donoghue","email":"bod.linux@nxsw.ie"},"content":"On 22/05/2026 15:37, Jai Luthra wrote:\n> --- a/src/libcamera/software_isp/debayer_egl.cpp\n> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> @@ -78,6 +78,19 @@ int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf\n>   \t\treturn 0;\n>   \t}\n> \n> +\tif (bayerFormat.bitDepth == 12 &&\n> +\t    bayerFormat.packing == BayerFormat::Packing::CSI2 &&\n> +\t    isStandardBayerOrder(bayerFormat.order)) {\n> +\t\tconfig.bpp = 12;\n> +\t\tconfig.patternSize.width = 2; /* 3 bytes per *2* pixels */\n> +\t\tconfig.patternSize.height = 2;\n> +\t\tconfig.outputFormats = std::vector<PixelFormat>({ formats::XRGB8888,\n> +\t\t\t\t\t\t\t\t  formats::ARGB8888,\n> +\t\t\t\t\t\t\t\t  formats::XBGR8888,\n> +\t\t\t\t\t\t\t\t  formats::ABGR8888 });\n> +\t\treturn 0;\n> +\t}\n> +\n>   \tLOG(Debayer, Error)\n>   \t\t<< \"Unsupported input format \" << inputFormat;\n\nA pleasingly small amount of change in debayer_egl.cpp to support this.\n\nI assume you have put the data through the shaders to verify it performs \nas expected ?\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 70223BDCBC\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 26 May 2026 17:52:44 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 78BE463021;\n\tTue, 26 May 2026 19:52:43 +0200 (CEST)","from mail-24422.protonmail.ch (mail-24422.protonmail.ch\n\t[109.224.244.22])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D8F2E62FD3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 May 2026 19:52:41 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxsw.ie header.i=@nxsw.ie header.b=\"FKTDU5rB\";\n\tdkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxsw.ie;\n\ts=protonmail; t=1779817960; x=1780077160;\n\tbh=DcYdH2osCKZDgbbVgnBtkttzuLcdua0S+i0ygrj1to8=;\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=FKTDU5rBltva9Z5AJSF/SknkKxJY906FDJYVToCbI+jus7POJfQFzDPQWMT3393mw\n\tc28Xyq/GwqaPY9zuYpWdWfM2rn8ophxLnUECCFMw83QM22hgls4U/lkSkyLejt+6h4\n\tDIdQW7JurF5GPZvOaywZg+WF8ixcOEuZZRL+LPxvGHN66/v51Im3Z2aXk5nV4KnS8k\n\tTrua9EN5KjrU1tvkDbGP2xFTaDm0lrHxROxxR2YsuOu8t0oIbCuGBuysYhl5f2F0ih\n\tvrp1ouEylBsLsZMFWfLYNxiPUQSR+Cc5StseAoiTfc6fjz0V9BMBIKaFyEjvj02LgN\n\tHoH/x/mOPw/oQ==","Date":"Tue, 26 May 2026 17:52:36 +0000","To":"Jai Luthra <jai.luthra@ideasonboard.com>,\n\tHans de Goede <johannes.goede@oss.qualcomm.com>,\n\tMilan Zamazal <mzamazal@redhat.com>","From":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","Message-ID":"<00f3f355-cc91-49eb-8a92-e8b3b0ac5d02@nxsw.ie>","In-Reply-To":"<20260522-swisp_12p-v1-1-e115c35387b7@ideasonboard.com>","References":"<20260522-swisp_12p-v1-1-e115c35387b7@ideasonboard.com>","Feedback-ID":"136405006:user:proton","X-Pm-Message-ID":"c8fadfe62e68b96f764c38df4a67ae0974d48dd3","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":38972,"web_url":"https://patchwork.libcamera.org/comment/38972/","msgid":"<177998367768.933414.10920178833171407376@freya>","date":"2026-05-28T15:54:37","subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","submitter":{"id":223,"url":"https://patchwork.libcamera.org/api/people/223/","name":"Jai Luthra","email":"jai.luthra@ideasonboard.com"},"content":"Hi Bryan,\n\nQuoting Bryan O'Donoghue (2026-05-26 23:22:36)\n> On 22/05/2026 15:37, Jai Luthra wrote:\n> > --- a/src/libcamera/software_isp/debayer_egl.cpp\n> > +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> > @@ -78,6 +78,19 @@ int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf\n> >               return 0;\n> >       }\n> > \n> > +     if (bayerFormat.bitDepth == 12 &&\n> > +         bayerFormat.packing == BayerFormat::Packing::CSI2 &&\n> > +         isStandardBayerOrder(bayerFormat.order)) {\n> > +             config.bpp = 12;\n> > +             config.patternSize.width = 2; /* 3 bytes per *2* pixels */\n> > +             config.patternSize.height = 2;\n> > +             config.outputFormats = std::vector<PixelFormat>({ formats::XRGB8888,\n> > +                                                               formats::ARGB8888,\n> > +                                                               formats::XBGR8888,\n> > +                                                               formats::ABGR8888 });\n> > +             return 0;\n> > +     }\n> > +\n> >       LOG(Debayer, Error)\n> >               << \"Unsupported input format \" << inputFormat;\n> \n> A pleasingly small amount of change in debayer_egl.cpp to support this.\n> \n\nIndeed, I was pleasantly surprised as well :-)\n\n\n> I assume you have put the data through the shaders to verify it performs \n> as expected ?\n> \n\nI tested with IMX678 (RAW12, RGGB), the output looked close enough visually\nto the CPU-based debayering.\n\nI couldn't test other bayer orderings though as the sensor shifts-by-1 when\nflipping to maintain the RGGB layout.\n\nIs there some other test source you usually use to thoroughly test the shader?\nI wonder if it would be easy enough to use pixpat [1] to generate packed 12\nbit test patterns. I can give that a try.\n\n[1] https://github.com/tomba/pixpat\n\n> ---\n> bod\n> \n\nThanks,\n    Jai","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 1D000BDCBC\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 28 May 2026 15:54:45 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 48C2262FEC;\n\tThu, 28 May 2026 17:54:44 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DB1A96175A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 May 2026 17:54:42 +0200 (CEST)","from mail.ideasonboard.com (unknown\n\t[IPv6:2401:4900:1c69:382:6f:8c15:9eec:bfe9])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id DE50C82A;\n\tThu, 28 May 2026 17:54:22 +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=\"KjhSW3x9\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1779983663;\n\tbh=lJ60y/KSZ4lER/FUtsuJ5hq1nu7h1nRTvSB0eam32oQ=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=KjhSW3x9Itzi4cxDDQ8SyySsq0I8I2upWNWb04mcZZxeX5IpObiVyjIB+AjVcV8+C\n\tU47jEQtQxHJVkxKu/1QPe9xn2wb3px+IWX+h5hvL93Ew35Las8OQaRGnqlZPnAJERI\n\t3n1cbZ+LSDWQijIAqsV8vk3LwlwqcTceREwBIsrA=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<00f3f355-cc91-49eb-8a92-e8b3b0ac5d02@nxsw.ie>","References":"<20260522-swisp_12p-v1-1-e115c35387b7@ideasonboard.com>\n\t<00f3f355-cc91-49eb-8a92-e8b3b0ac5d02@nxsw.ie>","Subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","From":"Jai Luthra <jai.luthra@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","To":"Bryan O'Donoghue <bod.linux@nxsw.ie>,\n\tHans de Goede <johannes.goede@oss.qualcomm.com>,\n\tMilan Zamazal <mzamazal@redhat.com>","Date":"Thu, 28 May 2026 21:24:37 +0530","Message-ID":"<177998367768.933414.10920178833171407376@freya>","User-Agent":"alot/0.13.dev20+g31692a239","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":38973,"web_url":"https://patchwork.libcamera.org/comment/38973/","msgid":"<177998374974.933414.9093154143154072540@freya>","date":"2026-05-28T15:55:49","subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","submitter":{"id":223,"url":"https://patchwork.libcamera.org/api/people/223/","name":"Jai Luthra","email":"jai.luthra@ideasonboard.com"},"content":"Hi Milan,\n\nThanks for the review.\n\nQuoting Milan Zamazal (2026-05-26 17:24:01)\n> Hi,\n> \n> thank you for the patch.\n> \n> Jai Luthra <jai.luthra@ideasonboard.com> writes:\n> \n> > Add support for debayering 12-bit CSI2 packed raw bayer formats.\n> >\n> > Also add support for the same in SwStats, skipping one 2x2 block\n> > horizontally and skipping every 3rd and 4th line vertically, like done\n> > for other raw bayer formats.\n> >\n> > GPUISP support was always present in the packed shaders (which already\n> > handle skipping the pixel with LSBs), so enable it too.\n> >\n> > Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>\n> > ---\n> > This is tested for RGGB12P using IMX678 on Arduino Uno Q. The sensor\n> > doesn't change bayer layout on flips, so I couldn't verify other\n> > layouts.\n> > ---\n> >  .../libcamera/internal/software_isp/swstats_cpu.h  |   3 +\n> >  src/libcamera/software_isp/debayer_cpu.cpp         | 107 +++++++++++++++++++++\n> >  src/libcamera/software_isp/debayer_cpu.h           |   9 ++\n> >  src/libcamera/software_isp/debayer_egl.cpp         |  13 +++\n> >  src/libcamera/software_isp/swstats_cpu.cpp         |  78 +++++++++++++++\n> >  5 files changed, 210 insertions(+)\n> >\n> > diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h\n> > index b5348c6f..13fa7582 100644\n> > --- a/include/libcamera/internal/software_isp/swstats_cpu.h\n> > +++ b/include/libcamera/internal/software_isp/swstats_cpu.h\n> > @@ -98,6 +98,9 @@ private:\n> >       /* Bayer 10 bpp packed */\n> >       void statsBGGR10PLine0(const uint8_t *src[], SwIspStats &stats);\n> >       void statsGBRG10PLine0(const uint8_t *src[], SwIspStats &stats);\n> > +     /* Bayer 12 bpp packed */\n> > +     void statsBGGR12PLine0(const uint8_t *src[], SwIspStats &stats);\n> > +     void statsGBRG12PLine0(const uint8_t *src[], SwIspStats &stats);\n> >  \n> >       void processBayerFrame2(MappedFrameBuffer &in);\n> >  \n> > diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n> > index 1f9b24da..2751dd30 100644\n> > --- a/src/libcamera/software_isp/debayer_cpu.cpp\n> > +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n> > @@ -351,6 +351,78 @@ void DebayerCpu::debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[])\n> >       }\n> >  }\n> >  \n> > +template<bool addAlphaByte, bool ccmEnabled>\n> > +void DebayerCpu::debayer12P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n> > +{\n> > +     const int widthInBytes = window_.width * 3 / 2;\n> > +     const uint8_t *prev = src[0];\n> > +     const uint8_t *curr = src[1];\n> > +     const uint8_t *next = src[2];\n> > +\n> > +     for (int x = 0; x < widthInBytes;) {\n> > +             /* Even pixel */\n> > +             BGGR_BGR888(2, 1, 1)\n> > +             /* Odd pixel RGGB -> GRBG */\n> \n> BGGR -> GBRG\n> \n\nOops, will fix.\n\n> > +             GBRG_BGR888(1, 2, 1)\n> > +             /* Skip 3rd src byte with 2 x 4 least-significant-bits */\n> > +             x++;\n> > +     }\n> > +}\n> > +\n> > +template<bool addAlphaByte, bool ccmEnabled>\n> > +void DebayerCpu::debayer12P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n> > +{\n> > +     const int widthInBytes = window_.width * 3 / 2;\n> > +     const uint8_t *prev = src[0];\n> > +     const uint8_t *curr = src[1];\n> > +     const uint8_t *next = src[2];\n> > +\n> > +     for (int x = 0; x < widthInBytes;) {\n> > +             /* Even pixel */\n> > +             GRBG_BGR888(2, 1, 1)\n> > +             /* Odd pixel RGGB -> GRBG */\n> \n> GRBG -> RGGB\n> \n> > +             RGGB_BGR888(1, 2, 1)\n> > +             /* Skip 3rd src byte with 2 x 4 least-significant-bits */\n> > +             x++;\n> > +     }\n> > +}\n> > +\n> > +template<bool addAlphaByte, bool ccmEnabled>\n> > +void DebayerCpu::debayer12P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[])\n> > +{\n> > +     const int widthInBytes = window_.width * 3 / 2;\n> > +     const uint8_t *prev = src[0];\n> > +     const uint8_t *curr = src[1];\n> > +     const uint8_t *next = src[2];\n> > +\n> > +     for (int x = 0; x < widthInBytes;) {\n> > +             /* Even pixel */\n> > +             GBRG_BGR888(2, 1, 1)\n> > +             /* Odd pixel RGGB -> GRBG */\n> \n> GBRG -> BGGR\n> \n> > +             BGGR_BGR888(1, 2, 1)\n> > +             /* Skip 3rd src byte with 2 x 4 least-significant-bits */\n> > +             x++;\n> > +     }\n> > +}\n> > +\n> > +template<bool addAlphaByte, bool ccmEnabled>\n> > +void DebayerCpu::debayer12P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[])\n> > +{\n> > +     const int widthInBytes = window_.width * 3 / 2;\n> > +     const uint8_t *prev = src[0];\n> > +     const uint8_t *curr = src[1];\n> > +     const uint8_t *next = src[2];\n> > +\n> > +     for (int x = 0; x < widthInBytes;) {\n> > +             /* Even pixel */\n> > +             RGGB_BGR888(2, 1, 1)\n> > +             /* Odd pixel RGGB -> GRBG */\n> > +             GRBG_BGR888(1, 2, 1)\n> > +             /* Skip 3rd src byte with 2 x 4 least-significant-bits */\n> > +             x++;\n> > +     }\n> > +}\n> \n> (I wish we could get rid of all the duplication here one day; not in\n> this patch.)\n> \n> > +\n> >  /*\n> >   * Setup the Debayer object according to the passed in parameters.\n> >   * Return 0 on success, a negative errno value on failure\n> > @@ -391,6 +463,21 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf\n> >               return 0;\n> >       }\n> >  \n> > +     if (bayerFormat.bitDepth == 12 &&\n> > +         bayerFormat.packing == BayerFormat::Packing::CSI2 &&\n> > +         isStandardBayerOrder(bayerFormat.order)) {\n> > +             config.bpp = 12;\n> > +             config.patternSize.width = 2; /* 3 bytes per *2* pixels */\n> > +             config.patternSize.height = 2;\n> > +             config.outputFormats = std::vector<PixelFormat>({ formats::RGB888,\n> > +                                                               formats::XRGB8888,\n> > +                                                               formats::ARGB8888,\n> > +                                                               formats::BGR888,\n> > +                                                               formats::XBGR8888,\n> > +                                                               formats::ABGR8888 });\n> \n> The output formats are all the same in all the cases, let's extract them\n> to a common variable?\n> \n\nAck.\n\n> > +             return 0;\n> > +     }\n> > +\n> >       LOG(Debayer, Info)\n> >               << \"Unsupported input format \" << inputFormat.toString();\n> >       return -EINVAL;\n> > @@ -538,6 +625,26 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat,\n> >               }\n> >       }\n> >  \n> > +     if (bayerFormat.bitDepth == 12 &&\n> > +         bayerFormat.packing == BayerFormat::Packing::CSI2) {\n> > +             switch (bayerFormat.order) {\n> > +             case BayerFormat::BGGR:\n> > +                     SET_DEBAYER_METHODS(debayer12P_BGBG_BGR888, debayer12P_GRGR_BGR888)\n> > +                     return 0;\n> > +             case BayerFormat::GBRG:\n> > +                     SET_DEBAYER_METHODS(debayer12P_GBGB_BGR888, debayer12P_RGRG_BGR888)\n> > +                     return 0;\n> > +             case BayerFormat::GRBG:\n> > +                     SET_DEBAYER_METHODS(debayer12P_GRGR_BGR888, debayer12P_BGBG_BGR888)\n> > +                     return 0;\n> > +             case BayerFormat::RGGB:\n> > +                     SET_DEBAYER_METHODS(debayer12P_RGRG_BGR888, debayer12P_GBGB_BGR888)\n> > +                     return 0;\n> > +             default:\n> > +                     break;\n> > +             }\n> > +     }\n> > +\n> >       return invalidFmt();\n> >  }\n> >  \n> > diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\n> > index 68da9508..5281c65c 100644\n> > --- a/src/libcamera/software_isp/debayer_cpu.h\n> > +++ b/src/libcamera/software_isp/debayer_cpu.h\n> > @@ -110,6 +110,15 @@ private:\n> >       void debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]);\n> >       template<bool addAlphaByte, bool ccmEnabled>\n> >       void debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]);\n> > +     /* CSI-2 packed 12-bit raw bayer format (all the 4 orders) */\n> > +     template<bool addAlphaByte, bool ccmEnabled>\n> > +     void debayer12P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);\n> > +     template<bool addAlphaByte, bool ccmEnabled>\n> > +     void debayer12P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);\n> > +     template<bool addAlphaByte, bool ccmEnabled>\n> > +     void debayer12P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]);\n> > +     template<bool addAlphaByte, bool ccmEnabled>\n> > +     void debayer12P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]);\n> >  \n> >       static int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config);\n> >       static int getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config);\n> > diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> > index eae4c57f..53adbdce 100644\n> > --- a/src/libcamera/software_isp/debayer_egl.cpp\n> > +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> > @@ -78,6 +78,19 @@ int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf\n> >               return 0;\n> >       }\n> >  \n> > +     if (bayerFormat.bitDepth == 12 &&\n> > +         bayerFormat.packing == BayerFormat::Packing::CSI2 &&\n> > +         isStandardBayerOrder(bayerFormat.order)) {\n> > +             config.bpp = 12;\n> > +             config.patternSize.width = 2; /* 3 bytes per *2* pixels */\n> > +             config.patternSize.height = 2;\n> > +             config.outputFormats = std::vector<PixelFormat>({ formats::XRGB8888,\n> > +                                                               formats::ARGB8888,\n> > +                                                               formats::XBGR8888,\n> > +                                                               formats::ABGR8888 });\n> \n> Here too.\n> \n> > +             return 0;\n> > +     }\n> > +\n> >       LOG(Debayer, Error)\n> >               << \"Unsupported input format \" << inputFormat;\n> >  \n> > diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\n> > index 0815ec9a..1deee942 100644\n> > --- a/src/libcamera/software_isp/swstats_cpu.cpp\n> > +++ b/src/libcamera/software_isp/swstats_cpu.cpp\n> > @@ -323,6 +323,58 @@ void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src[], SwIspStats &stats)\n> >       SWSTATS_FINISH_LINE_STATS()\n> >  }\n> >  \n> > +void SwStatsCpu::statsBGGR12PLine0(const uint8_t *src[], SwIspStats &stats)\n> > +{\n> > +     const uint8_t *src0 = src[1] + window_.x * 3 / 2;\n> > +     const uint8_t *src1 = src[2] + window_.x * 3 / 2;\n> > +     const unsigned int widthInBytes = window_.width * 3 / 2;\n> > +\n> > +     SWSTATS_START_LINE_STATS(uint8_t)\n> > +\n> > +     if (swapLines_)\n> > +             std::swap(src0, src1);\n> > +\n> > +     /* x += 6 sample every other 2x2 block */\n> > +     for (unsigned int x = 0; x < widthInBytes; x += 6) {\n> > +             b = src0[x];\n> > +             g = src0[x + 1];\n> > +             g2 = src1[x];\n> > +             r = src1[x + 1];\n> > +\n> > +             g = (g + g2) / 2;\n> > +\n> > +             SWSTATS_ACCUMULATE_LINE_STATS(1)\n> > +     }\n> > +\n> > +     SWSTATS_FINISH_LINE_STATS()\n> > +}\n> > +\n> > +void SwStatsCpu::statsGBRG12PLine0(const uint8_t *src[], SwIspStats &stats)\n> > +{\n> > +     const uint8_t *src0 = src[1] + window_.x * 3 / 2;\n> > +     const uint8_t *src1 = src[2] + window_.x * 3 / 2;\n> > +     const unsigned int widthInBytes = window_.width * 3 / 2;\n> > +\n> > +     SWSTATS_START_LINE_STATS(uint8_t)\n> > +\n> > +     if (swapLines_)\n> > +             std::swap(src0, src1);\n> > +\n> > +     /* x += 6 sample every other 2x2 block */\n> > +     for (unsigned int x = 0; x < widthInBytes; x += 6) {\n> > +             g = src0[x];\n> > +             b = src0[x + 1];\n> > +             r = src1[x];\n> > +             g2 = src1[x + 1];\n> > +\n> > +             g = (g + g2) / 2;\n> > +\n> > +             SWSTATS_ACCUMULATE_LINE_STATS(1)\n> > +     }\n> > +\n> > +     SWSTATS_FINISH_LINE_STATS()\n> > +}\n> > +\n> >  /**\n> >   * \\brief Reset state to start statistics gathering for a new frame\n> >   * \\param[in] frame The frame number\n> > @@ -466,6 +518,32 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg, unsigned int stat\n> >               }\n> >       }\n> >  \n> > +     if (bayerFormat.bitDepth == 12 &&\n> > +         bayerFormat.packing == BayerFormat::Packing::CSI2) {\n> > +             patternSize_.height = 2;\n> > +             patternSize_.width = 2; /* 3 bytes for *2* pixels */\n> > +             /* Skip every 3th and 4th line, sample every other 2x2 block */\n> > +             ySkipMask_ = 0x02;\n> > +             xShift_ = 0;\n> > +             sumShift_ = 0;\n> > +             processFrame_ = &SwStatsCpu::processBayerFrame2;\n> > +\n> > +             switch (bayerFormat.order) {\n> > +             case BayerFormat::BGGR:\n> > +             case BayerFormat::GRBG:\n> > +                     stats0_ = &SwStatsCpu::statsBGGR12PLine0;\n> > +                     swapLines_ = bayerFormat.order == BayerFormat::GRBG;\n> > +                     return 0;\n> > +             case BayerFormat::GBRG:\n> > +             case BayerFormat::RGGB:\n> > +                     stats0_ = &SwStatsCpu::statsGBRG12PLine0;\n> > +                     swapLines_ = bayerFormat.order == BayerFormat::RGGB;\n> > +                     return 0;\n> > +             default:\n> > +                     break;\n> > +             }\n> > +     }\n> > +\n> \n> This is almost identical to the 10-bit case, it should be worth to deduplicate.\n> \n\nWill do in v2.\n\nThanks,\n    Jai\n\n> >       LOG(SwStatsCpu, Info)\n> >               << \"Unsupported input format \" << inputCfg.pixelFormat.toString();\n> >       return -EINVAL;\n> >\n> > ---\n> > base-commit: 1f97c59d276922d387f7bfcfaa6d54b4084e43c1\n> > change-id: 20260522-swisp_12p-6ad22e4d08b0\n> >\n> > Best regards,\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 35C3CBDCBC\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 28 May 2026 15:55:56 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D514E63029;\n\tThu, 28 May 2026 17:55:55 +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 CF2C16175A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 May 2026 17:55:54 +0200 (CEST)","from mail.ideasonboard.com (unknown\n\t[IPv6:2401:4900:1c69:382:6f:8c15:9eec:bfe9])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id D8BD282A;\n\tThu, 28 May 2026 17:55:34 +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=\"c6PMHQvF\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1779983735;\n\tbh=CKpu1NUrgSDsxgZ8OJrIIlg54GPUH88IkWS/ezOE/Nk=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=c6PMHQvFTwME2Oq67v88YGW5mBkNwwiD97BEyRsUdQJH3YEX1WGrahY7M1RURBwTJ\n\ti3BlQ3o3WhDYhmC8f87TM1ZveFvPnGDNB255z/T4Lc63MA0kG7/2jDyCq1cxH/KLX2\n\tQ+inuxY+7vCHFlDZykUU4c1ZRjQdgvC7t63oz4ik=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<855x4a8jza.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","References":"<20260522-swisp_12p-v1-1-e115c35387b7@ideasonboard.com>\n\t<855x4a8jza.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","Subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","From":"Jai Luthra <jai.luthra@ideasonboard.com>","Cc":"Hans de Goede <johannes.goede@oss.qualcomm.com>,\n\tlibcamera-devel@lists.libcamera.org","To":"Milan Zamazal <mzamazal@redhat.com>","Date":"Thu, 28 May 2026 21:25:49 +0530","Message-ID":"<177998374974.933414.9093154143154072540@freya>","User-Agent":"alot/0.13.dev20+g31692a239","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":38975,"web_url":"https://patchwork.libcamera.org/comment/38975/","msgid":"<3564fd02-7f6b-4d47-8d2b-3586b8381b30@linaro.org>","date":"2026-06-01T23:35:44","subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","submitter":{"id":175,"url":"https://patchwork.libcamera.org/api/people/175/","name":"Bryan O'Donoghue","email":"bryan.odonoghue@linaro.org"},"content":"On 28/05/2026 16:54, Jai Luthra wrote:\n> Is there some other test source you usually use to thoroughly test the shader?\n\nSome test ?\n\nRun it once, if there is no blue smoke, ship it !\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 A891EBDCBC\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  1 Jun 2026 23:35:49 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B95076303C;\n\tTue,  2 Jun 2026 01:35:48 +0200 (CEST)","from mail-wm1-x336.google.com (mail-wm1-x336.google.com\n\t[IPv6:2a00:1450:4864:20::336])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A2D0062010\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  2 Jun 2026 01:35:46 +0200 (CEST)","by mail-wm1-x336.google.com with SMTP id\n\t5b1f17b1804b1-49041e84237so87237485e9.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 01 Jun 2026 16:35:46 -0700 (PDT)","from [192.168.0.35] ([109.76.233.76])\n\tby smtp.gmail.com with ESMTPSA id\n\t5b1f17b1804b1-4909c1035ebsm133225445e9.5.2026.06.01.16.35.45\n\t(version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n\tMon, 01 Jun 2026 16:35:45 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=linaro.org header.i=@linaro.org\n\theader.b=\"J0qRc9G5\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=linaro.org; s=google; t=1780356946; x=1780961746;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:in-reply-to:from:content-language\n\t:references:cc:to:subject:user-agent:mime-version:date:message-id\n\t:from:to:cc:subject:date:message-id:reply-to;\n\tbh=LOPYPpW9pngVgYNUwvZCkadrKQAqEwWYO0nVilPtdSs=;\n\tb=J0qRc9G5VRiEnSTRSWc+3SKyYGZYkLZjfulYYHeb/s/cJu2RWnk++JT65P9DCV8c1f\n\tMjLijAouC/FTjAEBSjU7M+E0FBZcPGRDWOQXuLpIjiEOZzpbF0P6ZFc+elf0+KpMypEM\n\tABf6ACbzomQYsNS4APZwbZnVAX4KPm3rESFhwCuEY/CUVTw7NLSw1BuFFr5Gt9M/RRkU\n\tDy/zf37X+94iOtkEYYf+8mjWn4hb4Ry4XD8tqqeU0A3UFVI2svFsknnPUNOfQ5iHm+As\n\tIDIVgiDb4qHqplHITPfXDKpfbpdfBunijjE2nbd2Ek74O9FzbfPHiiPbiYKTz6afPIEn\n\tcAYw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1780356946; x=1780961746;\n\th=content-transfer-encoding:in-reply-to:from:content-language\n\t:references:cc:to:subject:user-agent:mime-version:date:message-id\n\t:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=LOPYPpW9pngVgYNUwvZCkadrKQAqEwWYO0nVilPtdSs=;\n\tb=mAwkTtEUOyIXryYIJYuAMyTlnKTndLg30PpR/XmTgj7ljvkinlBgiJF17oes9n1tm/\n\tfrcBecr+Spsin6TM8Pd+W9Ika1nDvKEuab8TFz2dy6/PyiftP3mr7CLkZjrDXWLo02/2\n\tsMyLwOhWu2Ie6ezXeabhSNRk3ZbvIOP5ClS94zc5kI1f1KLWVFNWOmhM9dRQvVpvJlKY\n\txDN2bE1e+Zft+H0Ft2T2X5dJrKtRotHdWc2g15wSBp9qe7IdDMjQrGYPJp6n3IVLhibJ\n\tK/wG+yZpceKQXjOSFijLOfkgj5k7kIh3JeSRqZxFhCweuhpeazdcT11hGEyK9ez6AxVx\n\tbUag==","X-Gm-Message-State":"AOJu0Yxd/eBC+qpXRUi1QV1KoYFNDxQGKaNdE1QpZ7mtPB1KaRTJRqiv\n\tNOEF4EoIQU1bYTLNNq6/dRP9FBfKY+6UIu4/dQBiutMYlmV07+L75mS3cEIAPOMLgZs=","X-Gm-Gg":"Acq92OEfGsZMstVC3y4flm3cxwtmJMMZYgmEe+UFU71Phsh9sqG8S7iJWrXmvnUW7yF\n\t3W90Ws+xFwAmP8L0BLQ5h3X91V5Kvk5YPT05hhQyD/j09I5ZfGX5bIJ5jnqHhFkhVv4KdFgCs3Y\n\t+SuAdYBOncJrBqjbanltB6rypCJmpEV/iHX8sVplQQr9FNkc3CG2KI/OiyJAZ2hxq8UXGEK2ow/\n\tAH7PpTol6hNxpB6givVFL8PTx2hqtUUHoecfEVP4Np0EgAMjef8yCCo5evqiUVgDbEWgvGk4E5s\n\t3ZApiBfLq1tAJILyeQGGEY/JW6HKpCgH04mt6ASb0xHQV+6bu/qOpfybNmURhTcdlAPmYVn8fEY\n\tTCLc79W/EYXdvxNYFNr8RYJjhFIW9b98AnEzBn9iUqvv+egKTG2UcmDr9n1HhCE9ciBg2GV2G1l\n\tEZ4jg/J6K7gu9FqLTcaJwb5Kpov6z4njzW8NmENI639N02","X-Received":"by 2002:a05:600d:84ca:10b0:490:8b0b:d3b1 with SMTP id\n\t5b1f17b1804b1-490b0e8f03bmr14390385e9.12.1780356946097; \n\tMon, 01 Jun 2026 16:35:46 -0700 (PDT)","Message-ID":"<3564fd02-7f6b-4d47-8d2b-3586b8381b30@linaro.org>","Date":"Tue, 2 Jun 2026 00:35:44 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH] libcamera: software_isp: Support 12-bit CSI2 packed raw\n\tbayer formats","To":"Jai Luthra <jai.luthra@ideasonboard.com>,\n\tHans de Goede <johannes.goede@oss.qualcomm.com>,\n\tMilan Zamazal <mzamazal@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20260522-swisp_12p-v1-1-e115c35387b7@ideasonboard.com>\n\t<00f3f355-cc91-49eb-8a92-e8b3b0ac5d02@nxsw.ie>\n\t<bYPLwYfIICOeEsQ_VZ1iCx9m7mGRXyd9PaNq__x1w_NvD3ZrFDNcFnQK3d1fVNLJZW48zAiAdSecePW1u4p7Qg==@protonmail.internalid>\n\t<177998367768.933414.10920178833171407376@freya>","Content-Language":"en-US","From":"Bryan O'Donoghue <bryan.odonoghue@linaro.org>","In-Reply-To":"<177998367768.933414.10920178833171407376@freya>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"7bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]