{"id":20354,"url":"https://patchwork.libcamera.org/api/1.1/patches/20354/?format=json","web_url":"https://patchwork.libcamera.org/patch/20354/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20240618063227.197989-1-robert.mader@collabora.com>","date":"2024-06-18T06:31:59","name":"[v3] libcamera: debayer_cpu: Add 32bits/aligned output formats","commit_ref":"437e601653e69c82f5396979d99e7b9b5bb6086b","pull_url":null,"state":"accepted","archived":false,"hash":"2256264522859226fe5d6d105473479287c09689","submitter":{"id":140,"url":"https://patchwork.libcamera.org/api/1.1/people/140/?format=json","name":"Robert Mader","email":"robert.mader@collabora.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/20354/mbox/","series":[{"id":4407,"url":"https://patchwork.libcamera.org/api/1.1/series/4407/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4407","date":"2024-06-18T06:31:59","name":"[v3] libcamera: debayer_cpu: Add 32bits/aligned output formats","version":3,"mbox":"https://patchwork.libcamera.org/series/4407/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/20354/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/20354/checks/","tags":{},"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 DF650BE175\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 18 Jun 2024 06:33:09 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E552E654A4;\n\tTue, 18 Jun 2024 08:33:08 +0200 (CEST)","from madrid.collaboradmins.com (madrid.collaboradmins.com\n\t[46.235.227.194])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 71C47619F6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 18 Jun 2024 08:33:07 +0200 (CEST)","from thinkpad-t460p.fritz.box (cola.collaboradmins.com\n\t[195.201.22.229])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\tkey-exchange X25519 server-signature RSA-PSS (4096 bits)\n\tserver-digest SHA256)\n\t(No client certificate requested) (Authenticated sender: rmader)\n\tby madrid.collaboradmins.com (Postfix) with ESMTPSA id C4FF93781F9A; \n\tTue, 18 Jun 2024 06:33:06 +0000 (UTC)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=collabora.com header.i=@collabora.com\n\theader.b=\"a3ZuxDAO\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com;\n\ts=mail; t=1718692387;\n\tbh=XSIxrH4BSbD1JELnmAXB8+j1yUL7Gms58sklCAqCdyc=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=a3ZuxDAOXhc4s1Y7QH3L19nLuBZ1w0/OGCxBPNIDtQo1d2fcmVYutDPmIlxw8T2v4\n\tHEbV9iT2geTrU7+jlp1H7OtcZkCW2WPyKgGMreew6phTUncX8WCEsyhvNzKGI+rIw8\n\tPko0k4tHRr8nqLeZRYJIYbv7UTJfwtt4tIiMnB8u6rjn0TxM+y+1vBDGRG24sn4/Q3\n\t1y9pDfS9/ljD73li2RD3VP0+u21VZwIPKnwDbzRsfyE7kUuXvYEthRIbDYloehFZ6q\n\tOsSXdfXH6NbeeOz+u5UA6pPG206Z6k/KJql4e+dXbpD9WoKKtkJYebp5pd7Z37rl5B\n\tksxM8DxHUlV9g==","From":"Robert Mader <robert.mader@collabora.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Robert Mader <robert.mader@collabora.com>,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","Subject":"[PATCH v3] libcamera: debayer_cpu: Add 32bits/aligned output formats","Date":"Tue, 18 Jun 2024 08:31:59 +0200","Message-ID":"<20240618063227.197989-1-robert.mader@collabora.com>","X-Mailer":"git-send-email 2.45.2","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"In order to be more compatible with modern hardware and APIs. This\nnotably allows GL implementations to directly import the buffers more\noften and seems to be required for Wayland.\n\nFurther more, as we already enforce a 8 byte stride, these formats work\nbetter for clients that don't support padding - such as libwebrtc at the\ntime of writing.\n\nTested devices:\n - Librem5\n - PinePhone\n - Thinkpad X13s\n\nSigned-off-by: Robert Mader <robert.mader@collabora.com>\nTested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n---\n\nChanges in v3:\n - Remove previously introduced variable again and use C++ templates\n   instead in order to avoid runtime costs\n - Small cleanups and linting fixes\n\nChanges in v2:\n - Reduce code duplication by using a runtime variable instead\n - Small cleanups\n---\n src/libcamera/software_isp/debayer_cpu.cpp | 75 +++++++++++++++++-----\n src/libcamera/software_isp/debayer_cpu.h   | 10 +++\n 2 files changed, 69 insertions(+), 16 deletions(-)","diff":"diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\nindex c038eed4..f8d2677d 100644\n--- a/src/libcamera/software_isp/debayer_cpu.cpp\n+++ b/src/libcamera/software_isp/debayer_cpu.cpp\n@@ -74,6 +74,8 @@ DebayerCpu::~DebayerCpu()\n \t*dst++ = blue_[curr[x] / (div)];                                                      \\\n \t*dst++ = green_[(prev[x] + curr[x - p] + curr[x + n] + next[x]) / (4 * (div))];       \\\n \t*dst++ = red_[(prev[x - p] + prev[x + n] + next[x - p] + next[x + n]) / (4 * (div))]; \\\n+\tif constexpr (addAlphaByte)                                                           \\\n+\t\t*dst++ = 255;                                                                 \\\n \tx++;\n \n /*\n@@ -85,6 +87,8 @@ DebayerCpu::~DebayerCpu()\n \t*dst++ = blue_[(prev[x] + next[x]) / (2 * (div))];        \\\n \t*dst++ = green_[curr[x] / (div)];                         \\\n \t*dst++ = red_[(curr[x - p] + curr[x + n]) / (2 * (div))]; \\\n+\tif constexpr (addAlphaByte)                               \\\n+\t\t*dst++ = 255;                                     \\\n \tx++;\n \n /*\n@@ -96,6 +100,8 @@ DebayerCpu::~DebayerCpu()\n \t*dst++ = blue_[(curr[x - p] + curr[x + n]) / (2 * (div))]; \\\n \t*dst++ = green_[curr[x] / (div)];                          \\\n \t*dst++ = red_[(prev[x] + next[x]) / (2 * (div))];          \\\n+\tif constexpr (addAlphaByte)                                \\\n+\t\t*dst++ = 255;                                      \\\n \tx++;\n \n /*\n@@ -107,8 +113,11 @@ DebayerCpu::~DebayerCpu()\n \t*dst++ = blue_[(prev[x - p] + prev[x + n] + next[x - p] + next[x + n]) / (4 * (div))]; \\\n \t*dst++ = green_[(prev[x] + curr[x - p] + curr[x + n] + next[x]) / (4 * (div))];        \\\n \t*dst++ = red_[curr[x] / (div)];                                                        \\\n+\tif constexpr (addAlphaByte)                                                            \\\n+\t\t*dst++ = 255;                                                                  \\\n \tx++;\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tDECLARE_SRC_POINTERS(uint8_t)\n@@ -119,6 +128,7 @@ void DebayerCpu::debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n \t}\n }\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tDECLARE_SRC_POINTERS(uint8_t)\n@@ -129,6 +139,7 @@ void DebayerCpu::debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n \t}\n }\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tDECLARE_SRC_POINTERS(uint16_t)\n@@ -140,6 +151,7 @@ void DebayerCpu::debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n \t}\n }\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tDECLARE_SRC_POINTERS(uint16_t)\n@@ -151,6 +163,7 @@ void DebayerCpu::debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n \t}\n }\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tDECLARE_SRC_POINTERS(uint16_t)\n@@ -162,6 +175,7 @@ void DebayerCpu::debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n \t}\n }\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tDECLARE_SRC_POINTERS(uint16_t)\n@@ -173,6 +187,7 @@ void DebayerCpu::debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n \t}\n }\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tconst int widthInBytes = window_.width * 5 / 4;\n@@ -198,6 +213,7 @@ void DebayerCpu::debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])\n \t}\n }\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tconst int widthInBytes = window_.width * 5 / 4;\n@@ -218,6 +234,7 @@ void DebayerCpu::debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])\n \t}\n }\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tconst int widthInBytes = window_.width * 5 / 4;\n@@ -238,6 +255,7 @@ void DebayerCpu::debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[])\n \t}\n }\n \n+template<bool addAlphaByte>\n void DebayerCpu::debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[])\n {\n \tconst int widthInBytes = window_.width * 5 / 4;\n@@ -280,7 +298,12 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf\n \t\tconfig.bpp = (bayerFormat.bitDepth + 7) & ~7;\n \t\tconfig.patternSize.width = 2;\n \t\tconfig.patternSize.height = 2;\n-\t\tconfig.outputFormats = std::vector<PixelFormat>({ formats::RGB888, formats::BGR888 });\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 \t\treturn 0;\n \t}\n \n@@ -290,7 +313,12 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf\n \t\tconfig.bpp = 10;\n \t\tconfig.patternSize.width = 4; /* 5 bytes per *4* pixels */\n \t\tconfig.patternSize.height = 2;\n-\t\tconfig.outputFormats = std::vector<PixelFormat>({ formats::RGB888, formats::BGR888 });\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 \t\treturn 0;\n \t}\n \n@@ -306,6 +334,12 @@ int DebayerCpu::getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &c\n \t\treturn 0;\n \t}\n \n+\tif (outputFormat == formats::XRGB8888 || outputFormat == formats::ARGB8888 ||\n+\t    outputFormat == formats::XBGR8888 || outputFormat == formats::ABGR8888) {\n+\t\tconfig.bpp = 32;\n+\t\treturn 0;\n+\t}\n+\n \tLOG(Debayer, Info)\n \t\t<< \"Unsupported output format \" << outputFormat.toString();\n \treturn -EINVAL;\n@@ -341,6 +375,7 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputF\n {\n \tBayerFormat bayerFormat =\n \t\tBayerFormat::fromPixelFormat(inputFormat);\n+\tbool addAlphaByte = false;\n \n \txShift_ = 0;\n \tswapRedBlueGains_ = false;\n@@ -351,8 +386,16 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputF\n \t};\n \n \tswitch (outputFormat) {\n+\tcase formats::XRGB8888:\n+\tcase formats::ARGB8888:\n+\t\taddAlphaByte = true;\n+\t\t[[fallthrough]];\n \tcase formats::RGB888:\n \t\tbreak;\n+\tcase formats::XBGR8888:\n+\tcase formats::ABGR8888:\n+\t\taddAlphaByte = true;\n+\t\t[[fallthrough]];\n \tcase formats::BGR888:\n \t\t/* Swap R and B in bayer order to generate BGR888 instead of RGB888 */\n \t\tswapRedBlueGains_ = true;\n@@ -383,16 +426,16 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputF\n \t    isStandardBayerOrder(bayerFormat.order)) {\n \t\tswitch (bayerFormat.bitDepth) {\n \t\tcase 8:\n-\t\t\tdebayer0_ = &DebayerCpu::debayer8_BGBG_BGR888;\n-\t\t\tdebayer1_ = &DebayerCpu::debayer8_GRGR_BGR888;\n+\t\t\tdebayer0_ = addAlphaByte ? &DebayerCpu::debayer8_BGBG_BGR888<true> : &DebayerCpu::debayer8_BGBG_BGR888<false>;\n+\t\t\tdebayer1_ = addAlphaByte ? &DebayerCpu::debayer8_GRGR_BGR888<true> : &DebayerCpu::debayer8_GRGR_BGR888<false>;\n \t\t\tbreak;\n \t\tcase 10:\n-\t\t\tdebayer0_ = &DebayerCpu::debayer10_BGBG_BGR888;\n-\t\t\tdebayer1_ = &DebayerCpu::debayer10_GRGR_BGR888;\n+\t\t\tdebayer0_ = addAlphaByte ? &DebayerCpu::debayer10_BGBG_BGR888<true> : &DebayerCpu::debayer10_BGBG_BGR888<false>;\n+\t\t\tdebayer1_ = addAlphaByte ? &DebayerCpu::debayer10_GRGR_BGR888<true> : &DebayerCpu::debayer10_GRGR_BGR888<false>;\n \t\t\tbreak;\n \t\tcase 12:\n-\t\t\tdebayer0_ = &DebayerCpu::debayer12_BGBG_BGR888;\n-\t\t\tdebayer1_ = &DebayerCpu::debayer12_GRGR_BGR888;\n+\t\t\tdebayer0_ = addAlphaByte ? &DebayerCpu::debayer12_BGBG_BGR888<true> : &DebayerCpu::debayer12_BGBG_BGR888<false>;\n+\t\t\tdebayer1_ = addAlphaByte ? &DebayerCpu::debayer12_GRGR_BGR888<true> : &DebayerCpu::debayer12_GRGR_BGR888<false>;\n \t\t\tbreak;\n \t\t}\n \t\tsetupStandardBayerOrder(bayerFormat.order);\n@@ -403,20 +446,20 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputF\n \t    bayerFormat.packing == BayerFormat::Packing::CSI2) {\n \t\tswitch (bayerFormat.order) {\n \t\tcase BayerFormat::BGGR:\n-\t\t\tdebayer0_ = &DebayerCpu::debayer10P_BGBG_BGR888;\n-\t\t\tdebayer1_ = &DebayerCpu::debayer10P_GRGR_BGR888;\n+\t\t\tdebayer0_ = addAlphaByte ? &DebayerCpu::debayer10P_BGBG_BGR888<true> : &DebayerCpu::debayer10P_BGBG_BGR888<false>;\n+\t\t\tdebayer1_ = addAlphaByte ? &DebayerCpu::debayer10P_GRGR_BGR888<true> : &DebayerCpu::debayer10P_GRGR_BGR888<false>;\n \t\t\treturn 0;\n \t\tcase BayerFormat::GBRG:\n-\t\t\tdebayer0_ = &DebayerCpu::debayer10P_GBGB_BGR888;\n-\t\t\tdebayer1_ = &DebayerCpu::debayer10P_RGRG_BGR888;\n+\t\t\tdebayer0_ = addAlphaByte ? &DebayerCpu::debayer10P_GBGB_BGR888<true> : &DebayerCpu::debayer10P_GBGB_BGR888<false>;\n+\t\t\tdebayer1_ = addAlphaByte ? &DebayerCpu::debayer10P_RGRG_BGR888<true> : &DebayerCpu::debayer10P_RGRG_BGR888<false>;\n \t\t\treturn 0;\n \t\tcase BayerFormat::GRBG:\n-\t\t\tdebayer0_ = &DebayerCpu::debayer10P_GRGR_BGR888;\n-\t\t\tdebayer1_ = &DebayerCpu::debayer10P_BGBG_BGR888;\n+\t\t\tdebayer0_ = addAlphaByte ? &DebayerCpu::debayer10P_GRGR_BGR888<true> : &DebayerCpu::debayer10P_GRGR_BGR888<false>;\n+\t\t\tdebayer1_ = addAlphaByte ? &DebayerCpu::debayer10P_BGBG_BGR888<true> : &DebayerCpu::debayer10P_BGBG_BGR888<false>;\n \t\t\treturn 0;\n \t\tcase BayerFormat::RGGB:\n-\t\t\tdebayer0_ = &DebayerCpu::debayer10P_RGRG_BGR888;\n-\t\t\tdebayer1_ = &DebayerCpu::debayer10P_GBGB_BGR888;\n+\t\t\tdebayer0_ = addAlphaByte ? &DebayerCpu::debayer10P_RGRG_BGR888<true> : &DebayerCpu::debayer10P_RGRG_BGR888<false>;\n+\t\t\tdebayer1_ = addAlphaByte ? &DebayerCpu::debayer10P_GBGB_BGR888<true> : &DebayerCpu::debayer10P_GBGB_BGR888<false>;\n \t\t\treturn 0;\n \t\tdefault:\n \t\t\tbreak;\ndiff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\nindex be7dcdca..1dac6435 100644\n--- a/src/libcamera/software_isp/debayer_cpu.h\n+++ b/src/libcamera/software_isp/debayer_cpu.h\n@@ -85,18 +85,28 @@ private:\n \tusing debayerFn = void (DebayerCpu::*)(uint8_t *dst, const uint8_t *src[]);\n \n \t/* 8-bit raw bayer format */\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);\n \t/* unpacked 10-bit raw bayer format */\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);\n \t/* unpacked 12-bit raw bayer format */\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);\n \t/* CSI-2 packed 10-bit raw bayer format (all the 4 orders) */\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]);\n+\ttemplate<bool addAlphaByte>\n \tvoid debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]);\n \n \tstruct DebayerInputConfig {\n","prefixes":["v3"]}