diff options
Diffstat (limited to 'users/flokli/ipu6-softisp/libcamera')
21 files changed, 90 insertions, 5648 deletions
diff --git a/users/flokli/ipu6-softisp/libcamera/0016-libcamera-Add-support-for-IGIG_GBGR_IGIG_GRGB-bayer-.patch b/users/flokli/ipu6-softisp/libcamera/0001-libcamera-Add-support-for-IGIG_GBGR_IGIG_GRGB-bayer-.patch index 724b67033ff4..5340901edb94 100644 --- a/users/flokli/ipu6-softisp/libcamera/0016-libcamera-Add-support-for-IGIG_GBGR_IGIG_GRGB-bayer-.patch +++ b/users/flokli/ipu6-softisp/libcamera/0001-libcamera-Add-support-for-IGIG_GBGR_IGIG_GRGB-bayer-.patch @@ -1,7 +1,7 @@ -From e9580d30a1a79fce1ebd72ae74ceb4a3d1cf8fbb Mon Sep 17 00:00:00 2001 +From 0e94883c2f4f6164d40d4ea355449ba0864dc4f9 Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Tue, 19 Dec 2023 11:16:26 +0100 -Subject: [PATCH 16/21] libcamera: Add support for IGIG_GBGR_IGIG_GRGB bayer +Subject: [PATCH 1/3] libcamera: Add support for IGIG_GBGR_IGIG_GRGB bayer order DNU The ov01a1s sensor has the following bayer pattern (4x4 tile repeating): @@ -23,15 +23,15 @@ Signed-off-by: Hans de Goede <hdegoede@redhat.com> include/linux/media-bus-format.h | 4 +++- include/linux/videodev2.h | 3 +++ src/libcamera/bayer_format.cpp | 5 +++++ - src/libcamera/camera_sensor.cpp | 3 +++ src/libcamera/formats.cpp | 20 ++++++++++++++++++++ src/libcamera/formats.yaml | 5 +++++ + src/libcamera/sensor/camera_sensor.cpp | 3 +++ src/libcamera/v4l2_pixelformat.cpp | 4 ++++ - src/libcamera/v4l2_subdevice.cpp | 1 + - 10 files changed, 48 insertions(+), 2 deletions(-) + src/libcamera/v4l2_subdevice.cpp | 7 +++++++ + 10 files changed, 54 insertions(+), 2 deletions(-) diff --git a/include/libcamera/internal/bayer_format.h b/include/libcamera/internal/bayer_format.h -index 78ba3969..e77106c3 100644 +index 5c14bb5f..49b7f417 100644 --- a/include/libcamera/internal/bayer_format.h +++ b/include/libcamera/internal/bayer_format.h @@ -27,7 +27,8 @@ public: @@ -45,10 +45,10 @@ index 78ba3969..e77106c3 100644 enum class Packing : uint16_t { diff --git a/include/linux/drm_fourcc.h b/include/linux/drm_fourcc.h -index 1496e097..750ae8c9 100644 +index b4e1a092..070696bc 100644 --- a/include/linux/drm_fourcc.h +++ b/include/linux/drm_fourcc.h -@@ -405,6 +405,8 @@ extern "C" { +@@ -447,6 +447,8 @@ extern "C" { #define DRM_FORMAT_SGRBG10 fourcc_code('B', 'A', '1', '0') #define DRM_FORMAT_SGBRG10 fourcc_code('G', 'B', '1', '0') #define DRM_FORMAT_SBGGR10 fourcc_code('B', 'G', '1', '0') @@ -58,19 +58,19 @@ index 1496e097..750ae8c9 100644 /* 12-bit Bayer formats */ #define DRM_FORMAT_SRGGB12 fourcc_code('R', 'G', '1', '2') diff --git a/include/linux/media-bus-format.h b/include/linux/media-bus-format.h -index 0dfc11ee..c5fbda0e 100644 +index f05f747e..1b4a65db 100644 --- a/include/linux/media-bus-format.h +++ b/include/linux/media-bus-format.h -@@ -112,7 +112,7 @@ +@@ -121,7 +121,7 @@ #define MEDIA_BUS_FMT_YUV16_1X48 0x202a #define MEDIA_BUS_FMT_UYYVYY16_0_5X48 0x202b -/* Bayer - next is 0x3021 */ -+/* Bayer - next is 0x3022 */ ++/* Bayer - next is 0x3022 */ #define MEDIA_BUS_FMT_SBGGR8_1X8 0x3001 #define MEDIA_BUS_FMT_SGBRG8_1X8 0x3013 #define MEDIA_BUS_FMT_SGRBG8_1X8 0x3002 -@@ -145,6 +145,8 @@ +@@ -154,6 +154,8 @@ #define MEDIA_BUS_FMT_SGBRG16_1X16 0x301e #define MEDIA_BUS_FMT_SGRBG16_1X16 0x301f #define MEDIA_BUS_FMT_SRGGB16_1X16 0x3020 @@ -80,10 +80,10 @@ index 0dfc11ee..c5fbda0e 100644 /* JPEG compressed formats - next is 0x4002 */ #define MEDIA_BUS_FMT_JPEG_1X8 0x4001 diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h -index bfb315d6..13c6c9d3 100644 +index 0b5482a0..a51d6755 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h -@@ -678,6 +678,9 @@ struct v4l2_pix_format { +@@ -704,6 +704,9 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SGBRG16 v4l2_fourcc('G', 'B', '1', '6') /* 16 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SGRBG16 v4l2_fourcc('G', 'R', '1', '6') /* 16 GRGR.. BGBG.. */ #define V4L2_PIX_FMT_SRGGB16 v4l2_fourcc('R', 'G', '1', '6') /* 16 RGRG.. GBGB.. */ @@ -94,10 +94,10 @@ index bfb315d6..13c6c9d3 100644 /* HSV formats */ #define V4L2_PIX_FMT_HSV24 v4l2_fourcc('H', 'S', 'V', '3') diff --git a/src/libcamera/bayer_format.cpp b/src/libcamera/bayer_format.cpp -index 3bf15fb4..ae227540 100644 +index 014f716d..325887a2 100644 --- a/src/libcamera/bayer_format.cpp +++ b/src/libcamera/bayer_format.cpp -@@ -108,6 +108,8 @@ const std::map<BayerFormat, Formats, BayerFormatComparator> bayerToFormat{ +@@ -112,6 +112,8 @@ const std::map<BayerFormat, Formats, BayerFormatComparator> bayerToFormat{ { formats::SGRBG10, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10) } }, { { BayerFormat::RGGB, 10, BayerFormat::Packing::None }, { formats::SRGGB10, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10) } }, @@ -106,7 +106,7 @@ index 3bf15fb4..ae227540 100644 { { BayerFormat::BGGR, 10, BayerFormat::Packing::CSI2 }, { formats::SBGGR10_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P) } }, { { BayerFormat::GBRG, 10, BayerFormat::Packing::CSI2 }, -@@ -116,6 +118,8 @@ const std::map<BayerFormat, Formats, BayerFormatComparator> bayerToFormat{ +@@ -120,6 +122,8 @@ const std::map<BayerFormat, Formats, BayerFormatComparator> bayerToFormat{ { formats::SGRBG10_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P) } }, { { BayerFormat::RGGB, 10, BayerFormat::Packing::CSI2 }, { formats::SRGGB10_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P) } }, @@ -115,7 +115,7 @@ index 3bf15fb4..ae227540 100644 { { BayerFormat::BGGR, 10, BayerFormat::Packing::IPU3 }, { formats::SBGGR10_IPU3, V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SBGGR10) } }, { { BayerFormat::GBRG, 10, BayerFormat::Packing::IPU3 }, -@@ -193,6 +197,7 @@ const std::unordered_map<unsigned int, BayerFormat> mbusCodeToBayer{ +@@ -211,6 +215,7 @@ const std::unordered_map<unsigned int, BayerFormat> mbusCodeToBayer{ { MEDIA_BUS_FMT_SGBRG10_1X10, { BayerFormat::GBRG, 10, BayerFormat::Packing::None } }, { MEDIA_BUS_FMT_SGRBG10_1X10, { BayerFormat::GRBG, 10, BayerFormat::Packing::None } }, { MEDIA_BUS_FMT_SRGGB10_1X10, { BayerFormat::RGGB, 10, BayerFormat::Packing::None } }, @@ -123,25 +123,11 @@ index 3bf15fb4..ae227540 100644 { MEDIA_BUS_FMT_SBGGR12_1X12, { BayerFormat::BGGR, 12, BayerFormat::Packing::None } }, { MEDIA_BUS_FMT_SGBRG12_1X12, { BayerFormat::GBRG, 12, BayerFormat::Packing::None } }, { MEDIA_BUS_FMT_SGRBG12_1X12, { BayerFormat::GRBG, 12, BayerFormat::Packing::None } }, -diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp -index 0ef78d9c..f19f72ea 100644 ---- a/src/libcamera/camera_sensor.cpp -+++ b/src/libcamera/camera_sensor.cpp -@@ -510,6 +510,9 @@ int CameraSensor::initProperties() - case BayerFormat::MONO: - cfa = properties::draft::MONO; - break; -+ case BayerFormat::IGIG_GBGR_IGIG_GRGB: -+ cfa = properties::draft::RGB; -+ break; - } - - properties_.set(properties::draft::ColorFilterArrangement, cfa); diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp -index 447e6238..aef7d598 100644 +index cf41f2c2..13ac3253 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp -@@ -599,6 +599,16 @@ const std::map<PixelFormat, PixelFormatInfo> pixelFormatInfo{ +@@ -639,6 +639,16 @@ const std::map<PixelFormat, PixelFormatInfo> pixelFormatInfo{ .pixelsPerGroup = 2, .planes = {{ { 4, 1 }, { 0, 0 }, { 0, 0 } }}, } }, @@ -158,7 +144,7 @@ index 447e6238..aef7d598 100644 { formats::SBGGR10_CSI2P, { .name = "SBGGR10_CSI2P", .format = formats::SBGGR10_CSI2P, -@@ -639,6 +649,16 @@ const std::map<PixelFormat, PixelFormatInfo> pixelFormatInfo{ +@@ -679,6 +689,16 @@ const std::map<PixelFormat, PixelFormatInfo> pixelFormatInfo{ .pixelsPerGroup = 4, .planes = {{ { 5, 1 }, { 0, 0 }, { 0, 0 } }}, } }, @@ -176,10 +162,10 @@ index 447e6238..aef7d598 100644 .name = "SBGGR12", .format = formats::SBGGR12, diff --git a/src/libcamera/formats.yaml b/src/libcamera/formats.yaml -index 539ac0b3..0786a900 100644 +index fe027a7c..394f980c 100644 --- a/src/libcamera/formats.yaml +++ b/src/libcamera/formats.yaml -@@ -100,6 +100,8 @@ formats: +@@ -107,6 +107,8 @@ formats: fourcc: DRM_FORMAT_SGBRG10 - SBGGR10: fourcc: DRM_FORMAT_SBGGR10 @@ -188,7 +174,7 @@ index 539ac0b3..0786a900 100644 - SRGGB12: fourcc: DRM_FORMAT_SRGGB12 -@@ -144,6 +146,9 @@ formats: +@@ -151,6 +153,9 @@ formats: - SBGGR10_CSI2P: fourcc: DRM_FORMAT_SBGGR10 mod: MIPI_FORMAT_MOD_CSI2_PACKED @@ -198,11 +184,25 @@ index 539ac0b3..0786a900 100644 - SRGGB12_CSI2P: fourcc: DRM_FORMAT_SRGGB12 +diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp +index c6d7f801..77c396b9 100644 +--- a/src/libcamera/sensor/camera_sensor.cpp ++++ b/src/libcamera/sensor/camera_sensor.cpp +@@ -526,6 +526,9 @@ int CameraSensor::initProperties() + case BayerFormat::MONO: + cfa = properties::draft::MONO; + break; ++ case BayerFormat::IGIG_GBGR_IGIG_GRGB: ++ cfa = properties::draft::RGB; ++ break; + } + + properties_.set(properties::draft::ColorFilterArrangement, cfa); diff --git a/src/libcamera/v4l2_pixelformat.cpp b/src/libcamera/v4l2_pixelformat.cpp -index 5551c62e..53078d99 100644 +index 70568335..a2fbd644 100644 --- a/src/libcamera/v4l2_pixelformat.cpp +++ b/src/libcamera/v4l2_pixelformat.cpp -@@ -153,6 +153,8 @@ const std::map<V4L2PixelFormat, V4L2PixelFormat::Info> vpf2pf{ +@@ -159,6 +159,8 @@ const std::map<V4L2PixelFormat, V4L2PixelFormat::Info> vpf2pf{ { formats::SGRBG10, "10-bit Bayer GRGR/BGBG" } }, { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10), { formats::SRGGB10, "10-bit Bayer RGRG/GBGB" } }, @@ -211,7 +211,7 @@ index 5551c62e..53078d99 100644 { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P), { formats::SBGGR10_CSI2P, "10-bit Bayer BGBG/GRGR Packed" } }, { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P), -@@ -161,6 +163,8 @@ const std::map<V4L2PixelFormat, V4L2PixelFormat::Info> vpf2pf{ +@@ -167,6 +169,8 @@ const std::map<V4L2PixelFormat, V4L2PixelFormat::Info> vpf2pf{ { formats::SGRBG10_CSI2P, "10-bit Bayer GRGR/BGBG Packed" } }, { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P), { formats::SRGGB10_CSI2P, "10-bit Bayer RGRG/GBGB Packed" } }, @@ -221,17 +221,23 @@ index 5551c62e..53078d99 100644 { formats::SBGGR12, "12-bit Bayer BGBG/GRGR" } }, { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12), diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp -index 15e8206a..4ad37aaf 100644 +index 6da77775..0ba8c0de 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp -@@ -128,6 +128,7 @@ const std::map<uint32_t, V4L2SubdeviceFormatInfo> formatInfoMap = { - { MEDIA_BUS_FMT_SGBRG10_1X10, { 10, "SGBRG10_1X10", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGRBG10_1X10, { 10, "SGRBG10_1X10", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SRGGB10_1X10, { 10, "SRGGB10_1X10", PixelFormatInfo::ColourEncodingRAW } }, -+ { MEDIA_BUS_FMT_SIGIG_GBGR_IGIG_GRGB10_1X10, { 10, "SIGIG_GBGR_IGIG_GRGB10_1X10", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SBGGR12_1X12, { 12, "SBGGR12_1X12", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGBRG12_1X12, { 12, "SGBRG12_1X12", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGRBG12_1X12, { 12, "SGRBG12_1X12", PixelFormatInfo::ColourEncodingRAW } }, +@@ -595,6 +595,13 @@ const std::map<uint32_t, MediaBusFormatInfo> mediaBusFormatInfo{ + .bitsPerPixel = 10, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, ++ { MEDIA_BUS_FMT_SIGIG_GBGR_IGIG_GRGB10_1X10, { ++ .name = "SIGIG_GBGR_IGIG_GRGB10_1X10", ++ .code = MEDIA_BUS_FMT_SIGIG_GBGR_IGIG_GRGB10_1X10, ++ .type = MediaBusFormatInfo::Type::Image, ++ .bitsPerPixel = 10, ++ .colourEncoding = PixelFormatInfo::ColourEncodingRAW, ++ } }, + { MEDIA_BUS_FMT_SBGGR12_1X12, { + .name = "SBGGR12_1X12", + .code = MEDIA_BUS_FMT_SBGGR12_1X12, -- -2.43.2 +2.45.2 diff --git a/users/flokli/ipu6-softisp/libcamera/0001-libcamera-pipeline-simple-fix-size-adjustment-in-val.patch b/users/flokli/ipu6-softisp/libcamera/0001-libcamera-pipeline-simple-fix-size-adjustment-in-val.patch deleted file mode 100644 index b640ddaa24cd..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0001-libcamera-pipeline-simple-fix-size-adjustment-in-val.patch +++ /dev/null @@ -1,82 +0,0 @@ -From d86746fc1739f678e4bafe43f5047cba9b6b053e Mon Sep 17 00:00:00 2001 -From: Andrey Konovalov <andrey.konovalov@linaro.org> -Date: Mon, 11 Mar 2024 15:15:05 +0100 -Subject: [PATCH 01/21] libcamera: pipeline: simple: fix size adjustment in - validate() - -SimpleCameraConfiguration::validate() adjusts the configuration of its -streams (if the size is not in the outputSizes) to the captureSize. But -the captureSize itself can be not in the outputSizes, and then the -adjusted configuration won't be valid resulting in camera configuration -failure. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - src/libcamera/pipeline/simple/simple.cpp | 37 ++++++++++++++++++++++-- - 1 file changed, 35 insertions(+), 2 deletions(-) - -diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp -index 911051b2..a84f6760 100644 ---- a/src/libcamera/pipeline/simple/simple.cpp -+++ b/src/libcamera/pipeline/simple/simple.cpp -@@ -881,6 +881,30 @@ SimpleCameraConfiguration::SimpleCameraConfiguration(Camera *camera, - { - } - -+namespace { -+ -+static Size adjustSize(const Size &requestedSize, const SizeRange &supportedSizes) -+{ -+ ASSERT(supportedSizes.min <= supportedSizes.max); -+ -+ if (supportedSizes.min == supportedSizes.max) -+ return supportedSizes.max; -+ -+ unsigned int hStep = supportedSizes.hStep; -+ unsigned int vStep = supportedSizes.vStep; -+ -+ if (hStep == 0) -+ hStep = supportedSizes.max.width - supportedSizes.min.width; -+ if (vStep == 0) -+ vStep = supportedSizes.max.height - supportedSizes.min.height; -+ -+ Size adjusted = requestedSize.boundedTo(supportedSizes.max).expandedTo(supportedSizes.min); -+ -+ return adjusted.shrunkBy(supportedSizes.min).alignedDownTo(hStep, vStep).grownBy(supportedSizes.min); -+} -+ -+} /* namespace */ -+ - CameraConfiguration::Status SimpleCameraConfiguration::validate() - { - const CameraSensor *sensor = data_->sensor_.get(); -@@ -997,10 +1021,19 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate() - } - - if (!pipeConfig_->outputSizes.contains(cfg.size)) { -+ Size adjustedSize = pipeConfig_->captureSize; -+ /* -+ * The converter (when present) may not be able to output -+ * a size identical to its input size. The capture size is thus -+ * not guaranteed to be a valid output size. In such cases, use -+ * the smaller valid output size closest to the requested. -+ */ -+ if (!pipeConfig_->outputSizes.contains(adjustedSize)) -+ adjustedSize = adjustSize(cfg.size, pipeConfig_->outputSizes); - LOG(SimplePipeline, Debug) - << "Adjusting size from " << cfg.size -- << " to " << pipeConfig_->captureSize; -- cfg.size = pipeConfig_->captureSize; -+ << " to " << adjustedSize; -+ cfg.size = adjustedSize; - status = Adjusted; - } - --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0002-libcamera-internal-Move-dma_heaps.-h-cpp-to-common-d.patch b/users/flokli/ipu6-softisp/libcamera/0002-libcamera-internal-Move-dma_heaps.-h-cpp-to-common-d.patch deleted file mode 100644 index 450a0a21f19a..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0002-libcamera-internal-Move-dma_heaps.-h-cpp-to-common-d.patch +++ /dev/null @@ -1,350 +0,0 @@ -From 96e50c6a43352a9cb81d558fea27e580f2b26585 Mon Sep 17 00:00:00 2001 -From: Andrey Konovalov <andrey.konovalov@linaro.org> -Date: Mon, 11 Mar 2024 15:15:06 +0100 -Subject: [PATCH 02/21] libcamera: internal: Move dma_heaps.[h, cpp] to common - directories - -DmaHeap class is useful outside the RPi pipeline handler too. - -Move dma_heaps.h and dma_heaps.cpp to common directories. Update -the build files and RPi vc4 pipeline handler accordingly. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> -Reviewed-by: Naushir Patuck <naush@raspberrypi.com> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> ---- - .../libcamera/internal}/dma_heaps.h | 4 - - include/libcamera/internal/meson.build | 1 + - src/libcamera/dma_heaps.cpp | 127 ++++++++++++++++++ - src/libcamera/meson.build | 1 + - src/libcamera/pipeline/rpi/vc4/dma_heaps.cpp | 90 ------------- - src/libcamera/pipeline/rpi/vc4/meson.build | 1 - - src/libcamera/pipeline/rpi/vc4/vc4.cpp | 5 +- - 7 files changed, 131 insertions(+), 98 deletions(-) - rename {src/libcamera/pipeline/rpi/vc4 => include/libcamera/internal}/dma_heaps.h (92%) - create mode 100644 src/libcamera/dma_heaps.cpp - delete mode 100644 src/libcamera/pipeline/rpi/vc4/dma_heaps.cpp - -diff --git a/src/libcamera/pipeline/rpi/vc4/dma_heaps.h b/include/libcamera/internal/dma_heaps.h -similarity index 92% -rename from src/libcamera/pipeline/rpi/vc4/dma_heaps.h -rename to include/libcamera/internal/dma_heaps.h -index 0a4a8d86..cff8f140 100644 ---- a/src/libcamera/pipeline/rpi/vc4/dma_heaps.h -+++ b/include/libcamera/internal/dma_heaps.h -@@ -13,8 +13,6 @@ - - namespace libcamera { - --namespace RPi { -- - class DmaHeap - { - public: -@@ -27,6 +25,4 @@ private: - UniqueFD dmaHeapHandle_; - }; - --} /* namespace RPi */ -- - } /* namespace libcamera */ -diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build -index 7f1f3440..33eb0fb3 100644 ---- a/include/libcamera/internal/meson.build -+++ b/include/libcamera/internal/meson.build -@@ -25,6 +25,7 @@ libcamera_internal_headers = files([ - 'device_enumerator.h', - 'device_enumerator_sysfs.h', - 'device_enumerator_udev.h', -+ 'dma_heaps.h', - 'formats.h', - 'framebuffer.h', - 'ipa_manager.h', -diff --git a/src/libcamera/dma_heaps.cpp b/src/libcamera/dma_heaps.cpp -new file mode 100644 -index 00000000..38ef175a ---- /dev/null -+++ b/src/libcamera/dma_heaps.cpp -@@ -0,0 +1,127 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2020, Raspberry Pi Ltd -+ * -+ * dma_heaps.h - Helper class for dma-heap allocations. -+ */ -+ -+#include "libcamera/internal/dma_heaps.h" -+ -+#include <array> -+#include <fcntl.h> -+#include <sys/ioctl.h> -+#include <unistd.h> -+ -+#include <linux/dma-buf.h> -+#include <linux/dma-heap.h> -+ -+#include <libcamera/base/log.h> -+ -+/** -+ * \file dma_heaps.cpp -+ * \brief CMA dma-heap allocator -+ */ -+ -+/* -+ * /dev/dma_heap/linux,cma is the dma-heap allocator, which allows dmaheap-cma -+ * to only have to worry about importing. -+ * -+ * Annoyingly, should the cma heap size be specified on the kernel command line -+ * instead of DT, the heap gets named "reserved" instead. -+ */ -+static constexpr std::array<const char *, 2> heapNames = { -+ "/dev/dma_heap/linux,cma", -+ "/dev/dma_heap/reserved" -+}; -+ -+namespace libcamera { -+ -+LOG_DEFINE_CATEGORY(DmaHeap) -+ -+/** -+ * \class DmaHeap -+ * \brief Helper class for CMA dma-heap allocations -+ */ -+ -+/** -+ * \brief Construct a DmaHeap that owns a CMA dma-heap file descriptor -+ * -+ * Goes through the internal list of possible names of the CMA dma-heap devices -+ * until a CMA dma-heap device is successfully opened. If it fails to open any -+ * dma-heap device, an invalid DmaHeap object is constructed. A valid DmaHeap -+ * object owns a wrapped dma-heap file descriptor. -+ * -+ * Please check the new DmaHeap object with \ref DmaHeap::isValid before using it. -+ */ -+DmaHeap::DmaHeap() -+{ -+ for (const char *name : heapNames) { -+ int ret = ::open(name, O_RDWR | O_CLOEXEC, 0); -+ if (ret < 0) { -+ ret = errno; -+ LOG(DmaHeap, Debug) -+ << "Failed to open " << name << ": " -+ << strerror(ret); -+ continue; -+ } -+ -+ dmaHeapHandle_ = UniqueFD(ret); -+ break; -+ } -+ -+ if (!dmaHeapHandle_.isValid()) -+ LOG(DmaHeap, Error) << "Could not open any dmaHeap device"; -+} -+ -+/** -+ * \brief Destroy the DmaHeap instance -+ * -+ * Destroying a DmaHeap instance which owns a wrapped dma-heap file descriptor -+ * closes the descriptor automatically. -+ */ -+DmaHeap::~DmaHeap() = default; -+ -+/** -+ * \fn DmaHeap::isValid() -+ * \brief Check if the DmaHeap instance is valid -+ * \return True if the DmaHeap is valid, false otherwise -+ */ -+ -+/** -+ * \brief Allocate a dma-buf from the DmaHeap -+ * \param [in] name The name to set for the allocated buffer -+ * \param [in] size The size of the buffer to allocate -+ * \return The \ref UniqueFD of the allocated buffer -+ * -+ * Allocates a dma-buf with read/write access. -+ * If the allocation fails returns invalid UniqueFD. -+ */ -+UniqueFD DmaHeap::alloc(const char *name, std::size_t size) -+{ -+ int ret; -+ -+ if (!name) -+ return {}; -+ -+ struct dma_heap_allocation_data alloc = {}; -+ -+ alloc.len = size; -+ alloc.fd_flags = O_CLOEXEC | O_RDWR; -+ -+ ret = ::ioctl(dmaHeapHandle_.get(), DMA_HEAP_IOCTL_ALLOC, &alloc); -+ if (ret < 0) { -+ LOG(DmaHeap, Error) << "dmaHeap allocation failure for " << name; -+ return {}; -+ } -+ -+ UniqueFD allocFd(alloc.fd); -+ ret = ::ioctl(allocFd.get(), DMA_BUF_SET_NAME, name); -+ if (ret < 0) { -+ LOG(DmaHeap, Error) << "dmaHeap naming failure for " << name; -+ return {}; -+ } -+ -+ return allocFd; -+} -+ -+} /* namespace libcamera */ -diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build -index 45f63e93..3c5e43df 100644 ---- a/src/libcamera/meson.build -+++ b/src/libcamera/meson.build -@@ -17,6 +17,7 @@ libcamera_sources = files([ - 'delayed_controls.cpp', - 'device_enumerator.cpp', - 'device_enumerator_sysfs.cpp', -+ 'dma_heaps.cpp', - 'fence.cpp', - 'formats.cpp', - 'framebuffer.cpp', -diff --git a/src/libcamera/pipeline/rpi/vc4/dma_heaps.cpp b/src/libcamera/pipeline/rpi/vc4/dma_heaps.cpp -deleted file mode 100644 -index 317b1fc1..00000000 ---- a/src/libcamera/pipeline/rpi/vc4/dma_heaps.cpp -+++ /dev/null -@@ -1,90 +0,0 @@ --/* SPDX-License-Identifier: LGPL-2.1-or-later */ --/* -- * Copyright (C) 2020, Raspberry Pi Ltd -- * -- * dma_heaps.h - Helper class for dma-heap allocations. -- */ -- --#include "dma_heaps.h" -- --#include <array> --#include <fcntl.h> --#include <linux/dma-buf.h> --#include <linux/dma-heap.h> --#include <sys/ioctl.h> --#include <unistd.h> -- --#include <libcamera/base/log.h> -- --/* -- * /dev/dma-heap/linux,cma is the dma-heap allocator, which allows dmaheap-cma -- * to only have to worry about importing. -- * -- * Annoyingly, should the cma heap size be specified on the kernel command line -- * instead of DT, the heap gets named "reserved" instead. -- */ --static constexpr std::array<const char *, 2> heapNames = { -- "/dev/dma_heap/linux,cma", -- "/dev/dma_heap/reserved" --}; -- --namespace libcamera { -- --LOG_DECLARE_CATEGORY(RPI) -- --namespace RPi { -- --DmaHeap::DmaHeap() --{ -- for (const char *name : heapNames) { -- int ret = ::open(name, O_RDWR | O_CLOEXEC, 0); -- if (ret < 0) { -- ret = errno; -- LOG(RPI, Debug) << "Failed to open " << name << ": " -- << strerror(ret); -- continue; -- } -- -- dmaHeapHandle_ = UniqueFD(ret); -- break; -- } -- -- if (!dmaHeapHandle_.isValid()) -- LOG(RPI, Error) << "Could not open any dmaHeap device"; --} -- --DmaHeap::~DmaHeap() = default; -- --UniqueFD DmaHeap::alloc(const char *name, std::size_t size) --{ -- int ret; -- -- if (!name) -- return {}; -- -- struct dma_heap_allocation_data alloc = {}; -- -- alloc.len = size; -- alloc.fd_flags = O_CLOEXEC | O_RDWR; -- -- ret = ::ioctl(dmaHeapHandle_.get(), DMA_HEAP_IOCTL_ALLOC, &alloc); -- if (ret < 0) { -- LOG(RPI, Error) << "dmaHeap allocation failure for " -- << name; -- return {}; -- } -- -- UniqueFD allocFd(alloc.fd); -- ret = ::ioctl(allocFd.get(), DMA_BUF_SET_NAME, name); -- if (ret < 0) { -- LOG(RPI, Error) << "dmaHeap naming failure for " -- << name; -- return {}; -- } -- -- return allocFd; --} -- --} /* namespace RPi */ -- --} /* namespace libcamera */ -diff --git a/src/libcamera/pipeline/rpi/vc4/meson.build b/src/libcamera/pipeline/rpi/vc4/meson.build -index cdb049c5..386e2296 100644 ---- a/src/libcamera/pipeline/rpi/vc4/meson.build -+++ b/src/libcamera/pipeline/rpi/vc4/meson.build -@@ -1,7 +1,6 @@ - # SPDX-License-Identifier: CC0-1.0 - - libcamera_sources += files([ -- 'dma_heaps.cpp', - 'vc4.cpp', - ]) - -diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp -index 26102ea7..3a42e75e 100644 ---- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp -+++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp -@@ -12,12 +12,11 @@ - #include <libcamera/formats.h> - - #include "libcamera/internal/device_enumerator.h" -+#include "libcamera/internal/dma_heaps.h" - - #include "../common/pipeline_base.h" - #include "../common/rpi_stream.h" - --#include "dma_heaps.h" -- - using namespace std::chrono_literals; - - namespace libcamera { -@@ -87,7 +86,7 @@ public: - RPi::Device<Isp, 4> isp_; - - /* DMAHEAP allocation helper. */ -- RPi::DmaHeap dmaHeap_; -+ DmaHeap dmaHeap_; - SharedFD lsTable_; - - struct Config { --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0020-ov01a1s-HACK.patch b/users/flokli/ipu6-softisp/libcamera/0002-ov01a1s-HACK.patch index 343f04c8502b..61316d10427f 100644 --- a/users/flokli/ipu6-softisp/libcamera/0020-ov01a1s-HACK.patch +++ b/users/flokli/ipu6-softisp/libcamera/0002-ov01a1s-HACK.patch @@ -1,30 +1,30 @@ -From 2bde6e420571c6dc0ff25246620b4c987987f6be Mon Sep 17 00:00:00 2001 +From 5895f4ed8163780446665b99b8d5dc31d6f2b791 Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Tue, 19 Dec 2023 15:45:51 +0100 -Subject: [PATCH 20/21] ov01a1s HACK +Subject: [PATCH 2/3] ov01a1s HACK Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- - src/libcamera/camera_sensor.cpp | 6 ++++++ - src/libcamera/software_isp/debayer_cpu.cpp | 8 ++++++++ + src/libcamera/sensor/camera_sensor.cpp | 6 ++++++ + src/libcamera/software_isp/debayer_cpu.cpp | 7 +++++++ src/libcamera/software_isp/swstats_cpu.cpp | 4 ++++ - 3 files changed, 18 insertions(+) + 3 files changed, 17 insertions(+) -diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp -index f19f72ea..7ad4b9ef 100644 ---- a/src/libcamera/camera_sensor.cpp -+++ b/src/libcamera/camera_sensor.cpp -@@ -34,6 +34,9 @@ +diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp +index 77c396b9..628b12f4 100644 +--- a/src/libcamera/sensor/camera_sensor.cpp ++++ b/src/libcamera/sensor/camera_sensor.cpp +@@ -33,6 +33,9 @@ + */ namespace libcamera { - ++ +// HACK HACK +bool is_ov01a1s = false; -+ + LOG_DEFINE_CATEGORY(CameraSensor) - /** -@@ -426,6 +429,9 @@ int CameraSensor::initProperties() +@@ -442,6 +445,9 @@ int CameraSensor::initProperties() model_ = subdev_->model(); properties_.set(properties::Model, utils::toAscii(model_)); @@ -35,7 +35,7 @@ index f19f72ea..7ad4b9ef 100644 int ret = generateId(); if (ret) diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp -index 3be3cdfe..d6599805 100644 +index 8254bbe9..10ea29b1 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -23,6 +23,7 @@ @@ -46,7 +46,7 @@ index 3be3cdfe..d6599805 100644 /** * \class DebayerCpu * \brief Class for debayering on the CPU -@@ -262,6 +263,9 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf +@@ -275,6 +276,9 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf BayerFormat bayerFormat = BayerFormat::fromPixelFormat(inputFormat); @@ -56,7 +56,7 @@ index 3be3cdfe..d6599805 100644 if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) && bayerFormat.packing == BayerFormat::Packing::None && isStandardBayerOrder(bayerFormat.order)) { -@@ -330,7 +334,11 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputF +@@ -343,6 +347,9 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputF BayerFormat bayerFormat = BayerFormat::fromPixelFormat(inputFormat); @@ -64,12 +64,10 @@ index 3be3cdfe..d6599805 100644 + bayerFormat.order = BayerFormat::IGIG_GBGR_IGIG_GRGB; + xShift_ = 0; -+ swapRedBlueGains_ = false; - switch (outputFormat) { diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp -index be310f56..cda1894a 100644 +index 815c4d4f..0b310f80 100644 --- a/src/libcamera/software_isp/swstats_cpu.cpp +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -19,6 +19,7 @@ @@ -80,7 +78,7 @@ index be310f56..cda1894a 100644 /** * \class SwStatsCpu * \brief Class for gathering statistics on the CPU -@@ -271,6 +272,9 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg) +@@ -367,6 +368,9 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg) BayerFormat bayerFormat = BayerFormat::fromPixelFormat(inputCfg.pixelFormat); @@ -91,5 +89,5 @@ index be310f56..cda1894a 100644 setupStandardBayerOrder(bayerFormat.order) == 0) { switch (bayerFormat.bitDepth) { -- -2.43.2 +2.45.2 diff --git a/users/flokli/ipu6-softisp/libcamera/0021-libcamera-debayer_cpu-Make-the-minimum-size-1280x720.patch b/users/flokli/ipu6-softisp/libcamera/0003-libcamera-debayer_cpu-Make-the-minimum-size-1280x720.patch index a3af38c93c79..f250617bd3ad 100644 --- a/users/flokli/ipu6-softisp/libcamera/0021-libcamera-debayer_cpu-Make-the-minimum-size-1280x720.patch +++ b/users/flokli/ipu6-softisp/libcamera/0003-libcamera-debayer_cpu-Make-the-minimum-size-1280x720.patch @@ -1,7 +1,7 @@ -From a21bb26dcfcc00425f031421b87576f9c81e4824 Mon Sep 17 00:00:00 2001 +From 06add438e4fc53faca6e016bd582df0e7ac5a271 Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Wed, 24 Jan 2024 20:44:29 +0100 -Subject: [PATCH 21/21] libcamera: debayer_cpu: Make the minimum size 1280x720 +Subject: [PATCH 3/3] libcamera: debayer_cpu: Make the minimum size 1280x720 pipewire + firefox default to what looks like 640x480 if we export the entire supported cropping range. Hardcode 720p as minsize for now. @@ -12,31 +12,31 @@ Signed-off-by: Hans de Goede <hdegoede@redhat.com> 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp -index d6599805..5a06b191 100644 +index 10ea29b1..a354138b 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp -@@ -790,10 +790,17 @@ SizeRange DebayerCpu::sizes(PixelFormat inputFormat, const Size &inputSize) +@@ -805,10 +805,17 @@ SizeRange DebayerCpu::sizes(PixelFormat inputFormat, const Size &inputSize) return {}; } -- return SizeRange(Size(pattern_size.width, pattern_size.height), -- Size((inputSize.width - 2 * pattern_size.width) & ~(pattern_size.width - 1), -- (inputSize.height - 2 * border_height) & ~(pattern_size.height - 1)), -- pattern_size.width, pattern_size.height); +- return SizeRange(Size(patternSize.width, patternSize.height), +- Size((inputSize.width - 2 * patternSize.width) & ~(patternSize.width - 1), +- (inputSize.height - 2 * borderHeight) & ~(patternSize.height - 1)), +- patternSize.width, patternSize.height); + /* + * pipewire + firefox default to what looks like 640x480 + * if we export the entire supported cropping range. + * Hardcode 720p as minsize for now. Minsize should be -+ * Size(pattern_size.width, pattern_size.height) ++ * Size(patternSize.width, patternSize.height) + */ -+ unsigned int w = (inputSize.width - 2 * pattern_size.width) & ~(pattern_size.width - 1); -+ unsigned int h = (inputSize.height - 2 * pattern_size.height) & ~(pattern_size.height - 1); ++ unsigned int w = (inputSize.width - 2 * patternSize.width) & ~(patternSize.width - 1); ++ unsigned int h = (inputSize.height - 2 * patternSize.height) & ~(patternSize.height - 1); + return SizeRange(Size(std::min(w, 1280u), std::min(h, 720u)), + Size(w, h), -+ pattern_size.width, pattern_size.height); ++ patternSize.width, patternSize.height); } } /* namespace libcamera */ -- -2.43.2 +2.45.2 diff --git a/users/flokli/ipu6-softisp/libcamera/0003-libcamera-dma_heaps-extend-DmaHeap-class-to-support-.patch b/users/flokli/ipu6-softisp/libcamera/0003-libcamera-dma_heaps-extend-DmaHeap-class-to-support-.patch deleted file mode 100644 index 6e5ef9445a4b..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0003-libcamera-dma_heaps-extend-DmaHeap-class-to-support-.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 5df9bc3b2a3d86bcc8504896cc87d7fcb5aea3a4 Mon Sep 17 00:00:00 2001 -From: Andrey Konovalov <andrey.konovalov@linaro.org> -Date: Mon, 11 Mar 2024 15:15:07 +0100 -Subject: [PATCH 03/21] libcamera: dma_heaps: extend DmaHeap class to support - system heap - -Add an argument to the constructor to specify dma heaps type(s) -to use. Can be DmaHeapFlag::Cma and/or DmaHeapFlag::System. -By default DmaHeapFlag::Cma is used. If both DmaHeapFlag::Cma and -DmaHeapFlag::System are set, CMA heap is tried first. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - include/libcamera/internal/dma_heaps.h | 12 ++++- - src/libcamera/dma_heaps.cpp | 67 ++++++++++++++++++++------ - 2 files changed, 63 insertions(+), 16 deletions(-) - -diff --git a/include/libcamera/internal/dma_heaps.h b/include/libcamera/internal/dma_heaps.h -index cff8f140..80bf29e7 100644 ---- a/include/libcamera/internal/dma_heaps.h -+++ b/include/libcamera/internal/dma_heaps.h -@@ -9,6 +9,7 @@ - - #include <stddef.h> - -+#include <libcamera/base/flags.h> - #include <libcamera/base/unique_fd.h> - - namespace libcamera { -@@ -16,7 +17,14 @@ namespace libcamera { - class DmaHeap - { - public: -- DmaHeap(); -+ enum class DmaHeapFlag { -+ Cma = 1 << 0, -+ System = 1 << 1, -+ }; -+ -+ using DmaHeapFlags = Flags<DmaHeapFlag>; -+ -+ DmaHeap(DmaHeapFlags flags = DmaHeapFlag::Cma); - ~DmaHeap(); - bool isValid() const { return dmaHeapHandle_.isValid(); } - UniqueFD alloc(const char *name, std::size_t size); -@@ -25,4 +33,6 @@ private: - UniqueFD dmaHeapHandle_; - }; - -+LIBCAMERA_FLAGS_ENABLE_OPERATORS(DmaHeap::DmaHeapFlag) -+ - } /* namespace libcamera */ -diff --git a/src/libcamera/dma_heaps.cpp b/src/libcamera/dma_heaps.cpp -index 38ef175a..d0e33ce6 100644 ---- a/src/libcamera/dma_heaps.cpp -+++ b/src/libcamera/dma_heaps.cpp -@@ -19,9 +19,11 @@ - - /** - * \file dma_heaps.cpp -- * \brief CMA dma-heap allocator -+ * \brief dma-heap allocator - */ - -+namespace libcamera { -+ - /* - * /dev/dma_heap/linux,cma is the dma-heap allocator, which allows dmaheap-cma - * to only have to worry about importing. -@@ -29,42 +31,77 @@ - * Annoyingly, should the cma heap size be specified on the kernel command line - * instead of DT, the heap gets named "reserved" instead. - */ --static constexpr std::array<const char *, 2> heapNames = { -- "/dev/dma_heap/linux,cma", -- "/dev/dma_heap/reserved" -+ -+/** -+ * \struct DmaHeapInfo -+ * \brief Tells what type of dma-heap the dma-heap represented by the device node name is -+ * \var DmaHeapInfo::flag -+ * \brief The type of the dma-heap -+ * \var DmaHeapInfo::name -+ * \brief The dma-heap's device node name -+ */ -+struct DmaHeapInfo { -+ DmaHeap::DmaHeapFlag flag; -+ const char *name; - }; - --namespace libcamera { -+static constexpr std::array<DmaHeapInfo, 3> heapInfos = { -+ { /* CMA heap names first */ -+ { DmaHeap::DmaHeapFlag::Cma, "/dev/dma_heap/linux,cma" }, -+ { DmaHeap::DmaHeapFlag::Cma, "/dev/dma_heap/reserved" }, -+ { DmaHeap::DmaHeapFlag::System, "/dev/dma_heap/system" } } -+}; - - LOG_DEFINE_CATEGORY(DmaHeap) - - /** - * \class DmaHeap -- * \brief Helper class for CMA dma-heap allocations -+ * \brief Helper class for dma-heap allocations - */ - - /** -- * \brief Construct a DmaHeap that owns a CMA dma-heap file descriptor -+ * \enum DmaHeap::DmaHeapFlag -+ * \brief Type of the dma-heap -+ * \var DmaHeap::Cma -+ * \brief Allocate from a CMA dma-heap -+ * \var DmaHeap::System -+ * \brief Allocate from the system dma-heap -+ */ -+ -+/** -+ * \typedef DmaHeap::DmaHeapFlags -+ * \brief A bitwise combination of DmaHeap::DmaHeapFlag values -+ */ -+ -+/** -+ * \brief Construct a DmaHeap that owns a CMA or system dma-heap file descriptor -+ * \param [in] flags The type(s) of the dma-heap(s) to allocate from - * -- * Goes through the internal list of possible names of the CMA dma-heap devices -- * until a CMA dma-heap device is successfully opened. If it fails to open any -- * dma-heap device, an invalid DmaHeap object is constructed. A valid DmaHeap -- * object owns a wrapped dma-heap file descriptor. -+ * By default \a flags are set to DmaHeap::DmaHeapFlag::Cma. The constructor goes -+ * through the internal list of possible names of the CMA and system dma-heap devices -+ * until the dma-heap device of the requested type is successfully opened. If more -+ * than one dma-heap type is specified in flags the CMA heap is tried first. If it -+ * fails to open any dma-heap device an invalid DmaHeap object is constructed. -+ * A valid DmaHeap object owns a wrapped dma-heap file descriptor. - * - * Please check the new DmaHeap object with \ref DmaHeap::isValid before using it. - */ --DmaHeap::DmaHeap() -+DmaHeap::DmaHeap(DmaHeapFlags flags) - { -- for (const char *name : heapNames) { -- int ret = ::open(name, O_RDWR | O_CLOEXEC, 0); -+ for (const auto &info : heapInfos) { -+ if (!(flags & info.flag)) -+ continue; -+ -+ int ret = ::open(info.name, O_RDWR | O_CLOEXEC, 0); - if (ret < 0) { - ret = errno; - LOG(DmaHeap, Debug) -- << "Failed to open " << name << ": " -+ << "Failed to open " << info.name << ": " - << strerror(ret); - continue; - } - -+ LOG(DmaHeap, Debug) << "Using " << info.name; - dmaHeapHandle_ = UniqueFD(ret); - break; - } --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0004-libcamera-internal-Move-SharedMemObject-class-to-a-c.patch b/users/flokli/ipu6-softisp/libcamera/0004-libcamera-internal-Move-SharedMemObject-class-to-a-c.patch deleted file mode 100644 index 48f10aa47a99..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0004-libcamera-internal-Move-SharedMemObject-class-to-a-c.patch +++ /dev/null @@ -1,69 +0,0 @@ -From a6777760a2121f02808baecea504ac0e242f860b Mon Sep 17 00:00:00 2001 -From: Andrey Konovalov <andrey.konovalov@linaro.org> -Date: Mon, 11 Mar 2024 15:15:08 +0100 -Subject: [PATCH 04/21] libcamera: internal: Move SharedMemObject class to a - common directory - -Move SharedMemObject class out of RPi namespace and put it into -include/libcamera/internal so that everyone could use it. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> ---- - include/libcamera/internal/meson.build | 1 + - .../libcamera/internal}/shared_mem_object.h | 6 +----- - 2 files changed, 2 insertions(+), 5 deletions(-) - rename {src/libcamera/pipeline/rpi/common => include/libcamera/internal}/shared_mem_object.h (97%) - -diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build -index 33eb0fb3..5807dfd9 100644 ---- a/include/libcamera/internal/meson.build -+++ b/include/libcamera/internal/meson.build -@@ -39,6 +39,7 @@ libcamera_internal_headers = files([ - 'process.h', - 'pub_key.h', - 'request.h', -+ 'shared_mem_object.h', - 'source_paths.h', - 'sysfs.h', - 'v4l2_device.h', -diff --git a/src/libcamera/pipeline/rpi/common/shared_mem_object.h b/include/libcamera/internal/shared_mem_object.h -similarity index 97% -rename from src/libcamera/pipeline/rpi/common/shared_mem_object.h -rename to include/libcamera/internal/shared_mem_object.h -index aa56c220..98636b44 100644 ---- a/src/libcamera/pipeline/rpi/common/shared_mem_object.h -+++ b/include/libcamera/internal/shared_mem_object.h -@@ -6,8 +6,8 @@ - */ - #pragma once - --#include <cstddef> - #include <fcntl.h> -+#include <stddef.h> - #include <string> - #include <sys/mman.h> - #include <sys/stat.h> -@@ -19,8 +19,6 @@ - - namespace libcamera { - --namespace RPi { -- - template<class T> - class SharedMemObject - { -@@ -123,6 +121,4 @@ private: - T *obj_; - }; - --} /* namespace RPi */ -- - } /* namespace libcamera */ --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0005-libcamera-shared_mem_object-reorganize-the-code-and-.patch b/users/flokli/ipu6-softisp/libcamera/0005-libcamera-shared_mem_object-reorganize-the-code-and-.patch deleted file mode 100644 index d2143febf740..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0005-libcamera-shared_mem_object-reorganize-the-code-and-.patch +++ /dev/null @@ -1,403 +0,0 @@ -From f94af21adc1889706127d07c5425f44c9cec9a95 Mon Sep 17 00:00:00 2001 -From: Andrei Konovalov <andrey.konovalov.ynk@gmail.com> -Date: Mon, 11 Mar 2024 15:15:09 +0100 -Subject: [PATCH 05/21] libcamera: shared_mem_object: reorganize the code and - document the SharedMemObject class - -Split the parts which doesn't otherwise depend on the type T or -arguments Args out of the SharedMemObject class into a new -SharedMem class. - -Doxygen documentation by Dennis Bonke and Andrei Konovalov. - -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Co-developed-by: Dennis Bonke <admin@dennisbonke.com> -Signed-off-by: Dennis Bonke <admin@dennisbonke.com> -Signed-off-by: Andrei Konovalov <andrey.konovalov.ynk@gmail.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> ---- - .../libcamera/internal/shared_mem_object.h | 101 ++++++---- - src/libcamera/meson.build | 1 + - src/libcamera/shared_mem_object.cpp | 190 ++++++++++++++++++ - 3 files changed, 253 insertions(+), 39 deletions(-) - create mode 100644 src/libcamera/shared_mem_object.cpp - -diff --git a/include/libcamera/internal/shared_mem_object.h b/include/libcamera/internal/shared_mem_object.h -index 98636b44..43b07c9d 100644 ---- a/include/libcamera/internal/shared_mem_object.h -+++ b/include/libcamera/internal/shared_mem_object.h -@@ -6,12 +6,9 @@ - */ - #pragma once - --#include <fcntl.h> - #include <stddef.h> - #include <string> - #include <sys/mman.h> --#include <sys/stat.h> --#include <unistd.h> - #include <utility> - - #include <libcamera/base/class.h> -@@ -19,58 +16,92 @@ - - namespace libcamera { - -+class SharedMem -+{ -+public: -+ SharedMem() -+ : mem_(nullptr) -+ { -+ } -+ -+ SharedMem(const std::string &name, std::size_t size); -+ -+ SharedMem(SharedMem &&rhs) -+ { -+ this->name_ = std::move(rhs.name_); -+ this->fd_ = std::move(rhs.fd_); -+ this->mem_ = rhs.mem_; -+ rhs.mem_ = nullptr; -+ } -+ -+ virtual ~SharedMem() -+ { -+ if (mem_) -+ munmap(mem_, size_); -+ } -+ -+ /* Make SharedMem non-copyable for now. */ -+ LIBCAMERA_DISABLE_COPY(SharedMem) -+ -+ SharedMem &operator=(SharedMem &&rhs) -+ { -+ this->name_ = std::move(rhs.name_); -+ this->fd_ = std::move(rhs.fd_); -+ this->mem_ = rhs.mem_; -+ rhs.mem_ = nullptr; -+ return *this; -+ } -+ -+ const SharedFD &fd() const -+ { -+ return fd_; -+ } -+ -+ void *mem() const -+ { -+ return mem_; -+ } -+ -+private: -+ std::string name_; -+ SharedFD fd_; -+ size_t size_; -+protected: -+ void *mem_; -+}; -+ - template<class T> --class SharedMemObject -+class SharedMemObject : public SharedMem - { - public: - static constexpr std::size_t SIZE = sizeof(T); - - SharedMemObject() -- : obj_(nullptr) -+ : SharedMem(), obj_(nullptr) - { - } - - template<class... Args> - SharedMemObject(const std::string &name, Args &&...args) -- : name_(name), obj_(nullptr) -+ : SharedMem(name, SIZE), obj_(nullptr) - { -- void *mem; -- int ret; -- -- ret = memfd_create(name_.c_str(), MFD_CLOEXEC); -- if (ret < 0) -- return; -- -- fd_ = SharedFD(std::move(ret)); -- if (!fd_.isValid()) -- return; -- -- ret = ftruncate(fd_.get(), SIZE); -- if (ret < 0) -+ if (mem_ == nullptr) - return; - -- mem = mmap(nullptr, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, -- fd_.get(), 0); -- if (mem == MAP_FAILED) -- return; -- -- obj_ = new (mem) T(std::forward<Args>(args)...); -+ obj_ = new (mem_) T(std::forward<Args>(args)...); - } - - SharedMemObject(SharedMemObject<T> &&rhs) -+ : SharedMem(std::move(rhs)) - { -- this->name_ = std::move(rhs.name_); -- this->fd_ = std::move(rhs.fd_); - this->obj_ = rhs.obj_; - rhs.obj_ = nullptr; - } - - ~SharedMemObject() - { -- if (obj_) { -+ if (obj_) - obj_->~T(); -- munmap(obj_, SIZE); -- } - } - - /* Make SharedMemObject non-copyable for now. */ -@@ -78,8 +109,7 @@ public: - - SharedMemObject<T> &operator=(SharedMemObject<T> &&rhs) - { -- this->name_ = std::move(rhs.name_); -- this->fd_ = std::move(rhs.fd_); -+ SharedMem::operator=(std::move(rhs)); - this->obj_ = rhs.obj_; - rhs.obj_ = nullptr; - return *this; -@@ -105,19 +135,12 @@ public: - return *obj_; - } - -- const SharedFD &fd() const -- { -- return fd_; -- } -- - explicit operator bool() const - { - return !!obj_; - } - - private: -- std::string name_; -- SharedFD fd_; - T *obj_; - }; - -diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build -index 3c5e43df..94a95ae3 100644 ---- a/src/libcamera/meson.build -+++ b/src/libcamera/meson.build -@@ -41,6 +41,7 @@ libcamera_sources = files([ - 'process.cpp', - 'pub_key.cpp', - 'request.cpp', -+ 'shared_mem_object.cpp', - 'source_paths.cpp', - 'stream.cpp', - 'sysfs.cpp', -diff --git a/src/libcamera/shared_mem_object.cpp b/src/libcamera/shared_mem_object.cpp -new file mode 100644 -index 00000000..44fe74c2 ---- /dev/null -+++ b/src/libcamera/shared_mem_object.cpp -@@ -0,0 +1,190 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Raspberry Pi Ltd -+ * -+ * shared_mem_object.cpp - Helper class for shared memory allocations -+ */ -+ -+#include "libcamera/internal/shared_mem_object.h" -+ -+#include <sys/types.h> -+#include <unistd.h> -+ -+/** -+ * \file shared_mem_object.cpp -+ * \brief Helper class for shared memory allocations -+ */ -+ -+namespace libcamera { -+ -+/** -+ * \class SharedMem -+ * \brief Helper class for allocating shared memory -+ * -+ * Memory is allocated and exposed as a SharedFD for use across IPC boundaries. -+ * -+ * SharedMem allocates the shared memory of the given size and maps it. -+ * To check that the shared memory was allocated and mapped successfully, one -+ * needs to verify that the pointer to the shared memory returned by SharedMem::mem() -+ * is not nullptr. -+ * -+ * To access the shared memory from another process the SharedFD should be passed -+ * to that process, and then the shared memory should be mapped into that process -+ * address space by calling mmap(). -+ * -+ * A single memfd is created for every SharedMem. If there is a need to allocate -+ * a large number of objects in shared memory, these objects should be grouped -+ * together and use the shared memory allocated by a single SharedMem object if -+ * possible. This will help to minimize the number of created memfd's. -+ */ -+ -+/** -+ * \fn SharedMem::SharedMem(const std::string &name, std::size_t size) -+ * \brief Constructor for the SharedMem -+ * \param[in] name Name of the SharedMem -+ * \param[in] size Size of the shared memory to allocate and map -+ */ -+ -+/** -+ * \fn SharedMem::SharedMem(SharedMem &&rhs) -+ * \brief Move constructor for SharedMem -+ * \param[in] rhs The object to move -+ */ -+ -+/** -+ * \fn SharedMem::~SharedMem() -+ * \brief SharedMem destructor -+ * -+ * Unmaps the allocated shared memory. Decrements the shared memory descriptor use -+ * count. -+ */ -+ -+/** -+ * \fn SharedMem &SharedMem::operator=(SharedMem &&rhs) -+ * \brief Move constructor for SharedMem -+ * \param[in] rhs The object to move -+ */ -+ -+/** -+ * \fn const SharedFD &SharedMem::fd() const -+ * \brief Gets the file descriptor for the underlying shared memory -+ * \return The file descriptor -+ */ -+ -+/** -+ * \fn void *SharedMem::mem() const -+ * \brief Gets the pointer to the underlying shared memory -+ * \return The pointer to the shared memory -+ */ -+ -+SharedMem::SharedMem(const std::string &name, std::size_t size) -+ : name_(name), size_(size), mem_(nullptr) -+{ -+ int fd = memfd_create(name_.c_str(), MFD_CLOEXEC); -+ if (fd < 0) -+ return; -+ -+ fd_ = SharedFD(std::move(fd)); -+ if (!fd_.isValid()) -+ return; -+ -+ if (ftruncate(fd_.get(), size_) < 0) -+ return; -+ -+ mem_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, -+ fd_.get(), 0); -+ if (mem_ == MAP_FAILED) -+ mem_ = nullptr; -+} -+ -+/** -+ * \var SharedMem::mem_ -+ * \brief Pointer to the shared memory allocated -+ */ -+ -+/** -+ * \class SharedMemObject -+ * \brief Helper class for allocating objects in shared memory -+ * -+ * Memory is allocated and exposed as a SharedFD for use across IPC boundaries. -+ * -+ * Given the type of the object to be created in shared memory and the arguments -+ * to pass to this object's constructor, SharedMemObject allocates the shared memory -+ * of the size of the object and constructs the object in this memory. To ensure -+ * that the SharedMemObject was created successfully, one needs to verify that the -+ * overloaded bool() operator returns true. The object created in the shared memory -+ * can be accessed using the SharedMemObject::operator*() indirection operator. Its -+ * members can be accessed with the SharedMemObject::operator->() member of pointer -+ * operator. -+ * -+ * To access the object from another process the SharedFD should be passed to that -+ * process, and the shared memory should be mapped by calling mmap(). -+ * -+ * A single memfd is created for every SharedMemObject. If there is a need to allocate -+ * a large number of objects in shared memory, these objects should be grouped into a -+ * single large object to keep the number of created memfd's reasonably small. -+ */ -+ -+/** -+ * \var SharedMemObject::SIZE -+ * \brief The size of the object that is going to be stored here -+ */ -+ -+/** -+ * \fn SharedMemObject< T >::SharedMemObject(const std::string &name, Args &&...args) -+ * \brief Constructor for the SharedMemObject -+ * \param[in] name Name of the SharedMemObject -+ * \param[in] args Args to pass to the constructor of the object in shared memory -+ */ -+ -+/** -+ * \fn SharedMemObject::SharedMemObject(SharedMemObject<T> &&rhs) -+ * \brief Move constructor for SharedMemObject -+ * \param[in] rhs The object to move -+ */ -+ -+/** -+ * \fn SharedMemObject::~SharedMemObject() -+ * \brief SharedMemObject destructor -+ * -+ * Destroys the object created in the shared memory and then unmaps the shared memory. -+ * Decrements the shared memory descriptor use count. -+ */ -+ -+/** -+ * \fn SharedMemObject::operator=(SharedMemObject<T> &&rhs) -+ * \brief Operator= for SharedMemObject -+ * \param[in] rhs The SharedMemObject object to take the data from -+ */ -+ -+/** -+ * \fn SharedMemObject::operator->() -+ * \brief Operator-> for SharedMemObject -+ * \return The pointer to the object -+ */ -+ -+/** -+ * \fn const T *SharedMemObject::operator->() const -+ * \brief Operator-> for SharedMemObject -+ * \return The pointer to the const object -+ */ -+ -+/** -+ * \fn SharedMemObject::operator*() -+ * \brief Operator* for SharedMemObject -+ * \return The reference to the object -+ */ -+ -+/** -+ * \fn const T &SharedMemObject::operator*() const -+ * \brief Operator* for SharedMemObject -+ * \return Const reference to the object -+ */ -+ -+/** -+ * \fn SharedMemObject::operator bool() -+ * \brief Operator bool() for SharedMemObject -+ * \return True if the object was created OK in the shared memory, false otherwise -+ */ -+ -+} // namespace libcamera --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0006-libcamera-software_isp-Add-SwStatsCpu-class.patch b/users/flokli/ipu6-softisp/libcamera/0006-libcamera-software_isp-Add-SwStatsCpu-class.patch deleted file mode 100644 index 9f80b69f168c..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0006-libcamera-software_isp-Add-SwStatsCpu-class.patch +++ /dev/null @@ -1,523 +0,0 @@ -From 4259b01930333c6666a185d923e6e68ec915a4fd Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Mon, 11 Mar 2024 15:15:10 +0100 -Subject: [PATCH 06/21] libcamera: software_isp: Add SwStatsCpu class - -Add a CPU based SwStats implementation for SoftwareISP / SoftIPA use. - -This implementation offers a configure function + functions to gather -statistics on a line by line basis. This allows CPU based software -debayering to call into interlace debayering and statistics gathering -on a line by line bases while the input data is still hot in the cache. - -This implementation also allows specifying a window over which to gather -statistics instead of processing the whole frame. - -Doxygen documentation by Dennis Bonke. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> -Co-developed-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Co-developed-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Pavel Machek <pavel@ucw.cz> -Co-developed-by: Dennis Bonke <admin@dennisbonke.com> -Signed-off-by: Dennis Bonke <admin@dennisbonke.com> -Co-developed-by: Marttico <g.martti@gmail.com> -Signed-off-by: Marttico <g.martti@gmail.com> -Co-developed-by: Toon Langendam <t.langendam@gmail.com> -Signed-off-by: Toon Langendam <t.langendam@gmail.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - include/libcamera/internal/meson.build | 1 + - .../internal/software_isp/meson.build | 5 + - .../internal/software_isp/swisp_stats.h | 38 ++++ - src/libcamera/meson.build | 1 + - src/libcamera/software_isp/meson.build | 12 + - src/libcamera/software_isp/swstats_cpu.cpp | 208 ++++++++++++++++++ - src/libcamera/software_isp/swstats_cpu.h | 159 +++++++++++++ - 7 files changed, 424 insertions(+) - create mode 100644 include/libcamera/internal/software_isp/meson.build - create mode 100644 include/libcamera/internal/software_isp/swisp_stats.h - create mode 100644 src/libcamera/software_isp/meson.build - create mode 100644 src/libcamera/software_isp/swstats_cpu.cpp - create mode 100644 src/libcamera/software_isp/swstats_cpu.h - -diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build -index 5807dfd9..160fdc37 100644 ---- a/include/libcamera/internal/meson.build -+++ b/include/libcamera/internal/meson.build -@@ -50,3 +50,4 @@ libcamera_internal_headers = files([ - ]) - - subdir('converter') -+subdir('software_isp') -diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build -new file mode 100644 -index 00000000..66c9c3fb ---- /dev/null -+++ b/include/libcamera/internal/software_isp/meson.build -@@ -0,0 +1,5 @@ -+# SPDX-License-Identifier: CC0-1.0 -+ -+libcamera_internal_headers += files([ -+ 'swisp_stats.h', -+]) -diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h -new file mode 100644 -index 00000000..afe42c9a ---- /dev/null -+++ b/include/libcamera/internal/software_isp/swisp_stats.h -@@ -0,0 +1,38 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * -+ * swisp_stats.h - Statistics data format used by the software ISP and software IPA -+ */ -+ -+#pragma once -+ -+namespace libcamera { -+ -+/** -+ * \brief Struct that holds the statistics for the Software ISP. -+ */ -+struct SwIspStats { -+ /** -+ * \brief Holds the sum of all sampled red pixels. -+ */ -+ unsigned long sumR_; -+ /** -+ * \brief Holds the sum of all sampled green pixels. -+ */ -+ unsigned long sumG_; -+ /** -+ * \brief Holds the sum of all sampled blue pixels. -+ */ -+ unsigned long sumB_; -+ /** -+ * \brief Number of bins in the yHistogram. -+ */ -+ static constexpr unsigned int kYHistogramSize = 16; -+ /** -+ * \brief A histogram of luminance values. -+ */ -+ std::array<unsigned int, kYHistogramSize> yHistogram; -+}; -+ -+} /* namespace libcamera */ -diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build -index 94a95ae3..91e4cc60 100644 ---- a/src/libcamera/meson.build -+++ b/src/libcamera/meson.build -@@ -71,6 +71,7 @@ subdir('converter') - subdir('ipa') - subdir('pipeline') - subdir('proxy') -+subdir('software_isp') - - null_dep = dependency('', required : false) - -diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build -new file mode 100644 -index 00000000..fcfff74a ---- /dev/null -+++ b/src/libcamera/software_isp/meson.build -@@ -0,0 +1,12 @@ -+# SPDX-License-Identifier: CC0-1.0 -+ -+softisp_enabled = pipelines.contains('simple') -+summary({'SoftISP support' : softisp_enabled}, section : 'Configuration') -+ -+if not (softisp_enabled) -+ subdir_done() -+endif -+ -+libcamera_sources += files([ -+ 'swstats_cpu.cpp', -+]) -diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp -new file mode 100644 -index 00000000..448d0e4c ---- /dev/null -+++ b/src/libcamera/software_isp/swstats_cpu.cpp -@@ -0,0 +1,208 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * Copyright (C) 2023, Red Hat Inc. -+ * -+ * Authors: -+ * Hans de Goede <hdegoede@redhat.com> -+ * -+ * swstats_cpu.cpp - CPU based software statistics implementation -+ */ -+ -+#include "swstats_cpu.h" -+ -+#include <libcamera/base/log.h> -+ -+#include <libcamera/stream.h> -+ -+#include "libcamera/internal/bayer_format.h" -+ -+namespace libcamera { -+ -+/** -+ * \class SwStatsCpu -+ * \brief Class for gathering statistics on the CPU -+ * -+ * CPU based software ISP statistics implementation. -+ * -+ * This class offers a configure function + functions to gather statistics -+ * on a line by line basis. This allows CPU based software debayering to -+ * interlace debayering and statistics gathering on a line by line basis -+ * while the input data is still hot in the cache. -+ * -+ * It is also possible to specify a window over which to gather -+ * statistics instead of processing the whole frame. -+ */ -+ -+LOG_DEFINE_CATEGORY(SwStatsCpu) -+ -+SwStatsCpu::SwStatsCpu() -+{ -+ sharedStats_ = SharedMemObject<SwIspStats>("softIsp_stats"); -+ if (!sharedStats_.fd().isValid()) -+ LOG(SwStatsCpu, Error) -+ << "Failed to create shared memory for statistics"; -+} -+ -+static const unsigned int kRedYMul = 77; /* 0.299 * 256 */ -+static const unsigned int kGreenYMul = 150; /* 0.587 * 256 */ -+static const unsigned int kBlueYMul = 29; /* 0.114 * 256 */ -+ -+#define SWSTATS_START_LINE_STATS(pixel_t) \ -+ pixel_t r, g, g2, b; \ -+ unsigned int yVal; \ -+ \ -+ unsigned int sumR = 0; \ -+ unsigned int sumG = 0; \ -+ unsigned int sumB = 0; -+ -+#define SWSTATS_ACCUMULATE_LINE_STATS(div) \ -+ sumR += r; \ -+ sumG += g; \ -+ sumB += b; \ -+ \ -+ yVal = r * kRedYMul; \ -+ yVal += g * kGreenYMul; \ -+ yVal += b * kBlueYMul; \ -+ stats_.yHistogram[yVal * SwIspStats::kYHistogramSize / (256 * 256 * (div))]++; -+ -+#define SWSTATS_FINISH_LINE_STATS() \ -+ stats_.sumR_ += sumR; \ -+ stats_.sumG_ += sumG; \ -+ stats_.sumB_ += sumB; -+ -+void SwStatsCpu::statsBGGR10PLine0(const uint8_t *src[]) -+{ -+ const uint8_t *src0 = src[1] + window_.x * 5 / 4; -+ const uint8_t *src1 = src[2] + window_.x * 5 / 4; -+ const int widthInBytes = window_.width * 5 / 4; -+ -+ if (swapLines_) -+ std::swap(src0, src1); -+ -+ SWSTATS_START_LINE_STATS(uint8_t) -+ -+ /* x += 5 sample every other 2x2 block */ -+ for (int x = 0; x < widthInBytes; x += 5) { -+ /* BGGR */ -+ b = src0[x]; -+ g = src0[x + 1]; -+ g2 = src1[x]; -+ r = src1[x + 1]; -+ g = (g + g2) / 2; -+ /* Data is already 8 bits, divide by 1 */ -+ SWSTATS_ACCUMULATE_LINE_STATS(1) -+ } -+ -+ SWSTATS_FINISH_LINE_STATS() -+} -+ -+void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src[]) -+{ -+ const uint8_t *src0 = src[1] + window_.x * 5 / 4; -+ const uint8_t *src1 = src[2] + window_.x * 5 / 4; -+ const int widthInBytes = window_.width * 5 / 4; -+ -+ if (swapLines_) -+ std::swap(src0, src1); -+ -+ SWSTATS_START_LINE_STATS(uint8_t) -+ -+ /* x += 5 sample every other 2x2 block */ -+ for (int x = 0; x < widthInBytes; x += 5) { -+ /* GBRG */ -+ g = src0[x]; -+ b = src0[x + 1]; -+ r = src1[x]; -+ g2 = src1[x + 1]; -+ g = (g + g2) / 2; -+ /* Data is already 8 bits, divide by 1 */ -+ SWSTATS_ACCUMULATE_LINE_STATS(1) -+ } -+ -+ SWSTATS_FINISH_LINE_STATS() -+} -+ -+/** -+ * \brief Reset state to start statistics gathering for a new frame. -+ * -+ * This may only be called after a successful setWindow() call. -+ */ -+void SwStatsCpu::startFrame(void) -+{ -+ stats_.sumR_ = 0; -+ stats_.sumB_ = 0; -+ stats_.sumG_ = 0; -+ stats_.yHistogram.fill(0); -+} -+ -+/** -+ * \brief Finish statistics calculation for the current frame. -+ * -+ * This may only be called after a successful setWindow() call. -+ */ -+void SwStatsCpu::finishFrame(void) -+{ -+ *sharedStats_ = stats_; -+ statsReady.emit(0); -+} -+ -+/** -+ * \brief Configure the statistics object for the passed in input format. -+ * \param[in] inputCfg The input format -+ * -+ * \return 0 on success, a negative errno value on failure -+ */ -+int SwStatsCpu::configure(const StreamConfiguration &inputCfg) -+{ -+ BayerFormat bayerFormat = -+ BayerFormat::fromPixelFormat(inputCfg.pixelFormat); -+ -+ if (bayerFormat.bitDepth == 10 && -+ bayerFormat.packing == BayerFormat::Packing::CSI2) { -+ patternSize_.height = 2; -+ patternSize_.width = 4; /* 5 bytes per *4* pixels */ -+ /* Skip every 3th and 4th line, sample every other 2x2 block */ -+ ySkipMask_ = 0x02; -+ xShift_ = 0; -+ -+ switch (bayerFormat.order) { -+ case BayerFormat::BGGR: -+ case BayerFormat::GRBG: -+ stats0_ = &SwStatsCpu::statsBGGR10PLine0; -+ swapLines_ = bayerFormat.order == BayerFormat::GRBG; -+ return 0; -+ case BayerFormat::GBRG: -+ case BayerFormat::RGGB: -+ stats0_ = &SwStatsCpu::statsGBRG10PLine0; -+ swapLines_ = bayerFormat.order == BayerFormat::RGGB; -+ return 0; -+ default: -+ break; -+ } -+ } -+ -+ LOG(SwStatsCpu, Info) -+ << "Unsupported input format " << inputCfg.pixelFormat.toString(); -+ return -EINVAL; -+} -+ -+/** -+ * \brief Specify window coordinates over which to gather statistics. -+ * \param[in] window The window object. -+ */ -+void SwStatsCpu::setWindow(Rectangle window) -+{ -+ window_ = window; -+ -+ window_.x &= ~(patternSize_.width - 1); -+ window_.x += xShift_; -+ window_.y &= ~(patternSize_.height - 1); -+ -+ /* width_ - xShift_ to make sure the window fits */ -+ window_.width -= xShift_; -+ window_.width &= ~(patternSize_.width - 1); -+ window_.height &= ~(patternSize_.height - 1); -+} -+ -+} /* namespace libcamera */ -diff --git a/src/libcamera/software_isp/swstats_cpu.h b/src/libcamera/software_isp/swstats_cpu.h -new file mode 100644 -index 00000000..0ac9ae71 ---- /dev/null -+++ b/src/libcamera/software_isp/swstats_cpu.h -@@ -0,0 +1,159 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * Copyright (C) 2023, Red Hat Inc. -+ * -+ * Authors: -+ * Hans de Goede <hdegoede@redhat.com> -+ * -+ * swstats_cpu.h - CPU based software statistics implementation -+ */ -+ -+#pragma once -+ -+#include <stdint.h> -+ -+#include <libcamera/base/signal.h> -+ -+#include <libcamera/geometry.h> -+ -+#include "libcamera/internal/shared_mem_object.h" -+#include "libcamera/internal/software_isp/swisp_stats.h" -+ -+namespace libcamera { -+ -+class PixelFormat; -+struct StreamConfiguration; -+ -+class SwStatsCpu -+{ -+public: -+ SwStatsCpu(); -+ ~SwStatsCpu() = default; -+ -+ /** -+ * \brief Gets whether the statistics object is valid. -+ * -+ * \return true if it's valid, false otherwise -+ */ -+ bool isValid() const { return sharedStats_.fd().isValid(); } -+ -+ /** -+ * \brief Get the file descriptor for the statistics. -+ * -+ * \return the file descriptor -+ */ -+ const SharedFD &getStatsFD() { return sharedStats_.fd(); } -+ -+ /** -+ * \brief Get the pattern size. -+ * -+ * For some input-formats, e.g. Bayer data, processing is done multiple lines -+ * and/or columns at a time. Get width and height at which the (bayer) pattern -+ * repeats. Window values are rounded down to a multiple of this and the height -+ * also indicates if processLine2() should be called or not. -+ * This may only be called after a successful configure() call. -+ * -+ * \return the pattern size -+ */ -+ const Size &patternSize() { return patternSize_; } -+ -+ int configure(const StreamConfiguration &inputCfg); -+ void setWindow(Rectangle window); -+ void startFrame(); -+ void finishFrame(); -+ -+ /** -+ * \brief Process line 0. -+ * \param[in] y The y coordinate. -+ * \param[in] src The input data. -+ * -+ * This function processes line 0 for input formats with patternSize height == 1. -+ * It'll process line 0 and 1 for input formats with patternSize height >= 2. -+ * This function may only be called after a successful setWindow() call. -+ */ -+ void processLine0(unsigned int y, const uint8_t *src[]) -+ { -+ if ((y & ySkipMask_) || y < (unsigned int)window_.y || -+ y >= (window_.y + window_.height)) -+ return; -+ -+ (this->*stats0_)(src); -+ } -+ -+ /** -+ * \brief Process line 2 and 3. -+ * \param[in] y The y coordinate. -+ * \param[in] src The input data. -+ * -+ * This function processes line 2 and 3 for input formats with patternSize height == 4. -+ * This function may only be called after a successful setWindow() call. -+ */ -+ void processLine2(unsigned int y, const uint8_t *src[]) -+ { -+ if ((y & ySkipMask_) || y < (unsigned int)window_.y || -+ y >= (window_.y + window_.height)) -+ return; -+ -+ (this->*stats2_)(src); -+ } -+ -+ /** -+ * \brief Signals that the statistics are ready. -+ * -+ * The int parameter isn't actually used. -+ */ -+ Signal<int> statsReady; -+ -+private: -+ /** -+ * \brief Called when there is data to get statistics from. -+ * \param[in] src The input data -+ * -+ * These functions take an array of (patternSize_.height + 1) src -+ * pointers each pointing to a line in the source image. The middle -+ * element of the array will point to the actual line being processed. -+ * Earlier element(s) will point to the previous line(s) and later -+ * element(s) to the next line(s). -+ * -+ * See the documentation of DebayerCpu::debayerFn for more details. -+ */ -+ using statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[]); -+ -+ void statsBGGR10PLine0(const uint8_t *src[]); -+ void statsGBRG10PLine0(const uint8_t *src[]); -+ -+ /* Variables set by configure(), used every line */ -+ statsProcessFn stats0_; -+ statsProcessFn stats2_; -+ bool swapLines_; -+ -+ /** -+ * \brief Skip lines where this bitmask is set in y. -+ */ -+ unsigned int ySkipMask_; -+ -+ /** -+ * \brief Statistics window, set by setWindow(), used ever line. -+ */ -+ Rectangle window_; -+ -+ /** -+ * \brief The size of the bayer pattern. -+ * -+ * Valid sizes are: 2x2, 4x2 or 4x4. -+ */ -+ Size patternSize_; -+ -+ /** -+ * \brief The offset of x, applied to window_.x for bayer variants. -+ * -+ * This can either be 0 or 1. -+ */ -+ unsigned int xShift_; -+ -+ SharedMemObject<SwIspStats> sharedStats_; -+ SwIspStats stats_; -+}; -+ -+} /* namespace libcamera */ --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0007-libcamera-software_isp-Add-Debayer-base-class.patch b/users/flokli/ipu6-softisp/libcamera/0007-libcamera-software_isp-Add-Debayer-base-class.patch deleted file mode 100644 index 7c7170989666..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0007-libcamera-software_isp-Add-Debayer-base-class.patch +++ /dev/null @@ -1,255 +0,0 @@ -From 25e6893e46bd2174f6913eea79817988d9280706 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Mon, 11 Mar 2024 15:15:11 +0100 -Subject: [PATCH 07/21] libcamera: software_isp: Add Debayer base class - -Add a base class for debayer implementations. This is intended to be -suitable for both GPU (or otherwise) accelerated debayer implementations -as well as CPU based debayering. - -Doxygen documentation by Dennis Bonke. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> -Co-developed-by: Dennis Bonke <admin@dennisbonke.com> -Signed-off-by: Dennis Bonke <admin@dennisbonke.com> -Co-developed-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - .../internal/software_isp/debayer_params.h | 48 ++++++++ - .../internal/software_isp/meson.build | 1 + - src/libcamera/software_isp/debayer.cpp | 29 +++++ - src/libcamera/software_isp/debayer.h | 104 ++++++++++++++++++ - src/libcamera/software_isp/meson.build | 1 + - 5 files changed, 183 insertions(+) - create mode 100644 include/libcamera/internal/software_isp/debayer_params.h - create mode 100644 src/libcamera/software_isp/debayer.cpp - create mode 100644 src/libcamera/software_isp/debayer.h - -diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h -new file mode 100644 -index 00000000..98965fa1 ---- /dev/null -+++ b/include/libcamera/internal/software_isp/debayer_params.h -@@ -0,0 +1,48 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Red Hat Inc. -+ * -+ * Authors: -+ * Hans de Goede <hdegoede@redhat.com> -+ * -+ * debayer_params.h - DebayerParams header -+ */ -+ -+#pragma once -+ -+namespace libcamera { -+ -+/** -+ * \brief Struct to hold the debayer parameters. -+ */ -+struct DebayerParams { -+ /** -+ * \brief const value for 1.0 gain -+ */ -+ static constexpr unsigned int kGain10 = 256; -+ -+ /** -+ * \brief Red Gain -+ * -+ * 128 = 0.5, 256 = 1.0, 512 = 2.0, etc. -+ */ -+ unsigned int gainR; -+ /** -+ * \brief Green Gain -+ * -+ * 128 = 0.5, 256 = 1.0, 512 = 2.0, etc. -+ */ -+ unsigned int gainG; -+ /** -+ * \brief Blue Gain -+ * -+ * 128 = 0.5, 256 = 1.0, 512 = 2.0, etc. -+ */ -+ unsigned int gainB; -+ /** -+ * \brief Gamma correction, 1.0 is no correction -+ */ -+ float gamma; -+}; -+ -+} /* namespace libcamera */ -diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build -index 66c9c3fb..a620e16d 100644 ---- a/include/libcamera/internal/software_isp/meson.build -+++ b/include/libcamera/internal/software_isp/meson.build -@@ -1,5 +1,6 @@ - # SPDX-License-Identifier: CC0-1.0 - - libcamera_internal_headers += files([ -+ 'debayer_params.h', - 'swisp_stats.h', - ]) -diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp -new file mode 100644 -index 00000000..64f0b5a0 ---- /dev/null -+++ b/src/libcamera/software_isp/debayer.cpp -@@ -0,0 +1,29 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * Copyright (C) 2023, Red Hat Inc. -+ * -+ * Authors: -+ * Hans de Goede <hdegoede@redhat.com> -+ * -+ * debayer.cpp - debayer base class -+ */ -+ -+#include "debayer.h" -+ -+namespace libcamera { -+ -+/** -+ * \class Debayer -+ * \brief Base debayering class -+ * -+ * Base class that provides functions for setting up the debayering process. -+ */ -+ -+LOG_DEFINE_CATEGORY(Debayer) -+ -+Debayer::~Debayer() -+{ -+} -+ -+} /* namespace libcamera */ -diff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h -new file mode 100644 -index 00000000..8880ff99 ---- /dev/null -+++ b/src/libcamera/software_isp/debayer.h -@@ -0,0 +1,104 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * Copyright (C) 2023, Red Hat Inc. -+ * -+ * Authors: -+ * Hans de Goede <hdegoede@redhat.com> -+ * -+ * debayer.h - debayering base class -+ */ -+ -+#pragma once -+ -+#include <stdint.h> -+ -+#include <libcamera/base/log.h> -+#include <libcamera/base/signal.h> -+ -+#include <libcamera/geometry.h> -+#include <libcamera/stream.h> -+ -+#include "libcamera/internal/software_isp/debayer_params.h" -+ -+namespace libcamera { -+ -+class FrameBuffer; -+ -+LOG_DECLARE_CATEGORY(Debayer) -+ -+class Debayer -+{ -+public: -+ virtual ~Debayer() = 0; -+ -+ /** -+ * \brief Configure the debayer object according to the passed in parameters. -+ * \param[in] inputCfg The input configuration. -+ * \param[in] outputCfgs The output configurations. -+ * -+ * \return 0 on success, a negative errno on failure. -+ */ -+ virtual int configure(const StreamConfiguration &inputCfg, -+ const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs) = 0; -+ -+ /** -+ * \brief Get the width and height at which the bayer pattern repeats. -+ * \param[in] inputFormat The input format. -+ * -+ * Valid sizes are: 2x2, 4x2 or 4x4. -+ * -+ * \return pattern size or an empty size for unsupported inputFormats. -+ */ -+ virtual Size patternSize(PixelFormat inputFormat) = 0; -+ -+ /** -+ * \brief Get the supported output formats. -+ * \param[in] inputFormat The input format. -+ * -+ * \return all supported output formats or an empty vector if there are none. -+ */ -+ virtual std::vector<PixelFormat> formats(PixelFormat inputFormat) = 0; -+ -+ /** -+ * \brief Get the stride and the frame size. -+ * \param[in] outputFormat The output format. -+ * \param[in] size The output size. -+ * -+ * \return a tuple of the stride and the frame size, or a tuple with 0,0 if there is no valid output config. -+ */ -+ virtual std::tuple<unsigned int, unsigned int> -+ strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) = 0; -+ -+ /** -+ * \brief Process the bayer data into the requested format. -+ * \param[in] input The input buffer. -+ * \param[in] output The output buffer. -+ * \param[in] params The parameters to be used in debayering. -+ * -+ * \note DebayerParams is passed by value deliberately so that a copy is passed -+ * when this is run in another thread by invokeMethod(). -+ */ -+ virtual void process(FrameBuffer *input, FrameBuffer *output, DebayerParams params) = 0; -+ -+ /** -+ * \brief Get the supported output sizes for the given input format and size. -+ * \param[in] inputFormat The input format. -+ * \param[in] inputSize The input size. -+ * -+ * \return The valid size ranges or an empty range if there are none. -+ */ -+ virtual SizeRange sizes(PixelFormat inputFormat, const Size &inputSize) = 0; -+ -+ /** -+ * \brief Signals when the input buffer is ready. -+ */ -+ Signal<FrameBuffer *> inputBufferReady; -+ -+ /** -+ * \brief Signals when the output buffer is ready. -+ */ -+ Signal<FrameBuffer *> outputBufferReady; -+}; -+ -+} /* namespace libcamera */ -diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build -index fcfff74a..62095f61 100644 ---- a/src/libcamera/software_isp/meson.build -+++ b/src/libcamera/software_isp/meson.build -@@ -8,5 +8,6 @@ if not (softisp_enabled) - endif - - libcamera_sources += files([ -+ 'debayer.cpp', - 'swstats_cpu.cpp', - ]) --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0008-libcamera-software_isp-Add-DebayerCpu-class.patch b/users/flokli/ipu6-softisp/libcamera/0008-libcamera-software_isp-Add-DebayerCpu-class.patch deleted file mode 100644 index f549769f2fde..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0008-libcamera-software_isp-Add-DebayerCpu-class.patch +++ /dev/null @@ -1,825 +0,0 @@ -From 5f57a52ea1054cac73344d83ff605cba0df0d279 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Mon, 11 Mar 2024 15:15:12 +0100 -Subject: [PATCH 08/21] libcamera: software_isp: Add DebayerCpu class - -Add CPU based debayering implementation. This initial implementation -only supports debayering packed 10 bits per pixel bayer data in -the 4 standard bayer orders. - -Doxygen documentation by Dennis Bonke. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Co-developed-by: Dennis Bonke <admin@dennisbonke.com> -Signed-off-by: Dennis Bonke <admin@dennisbonke.com> -Co-developed-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Co-developed-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> ---- - src/libcamera/software_isp/debayer_cpu.cpp | 626 +++++++++++++++++++++ - src/libcamera/software_isp/debayer_cpu.h | 143 +++++ - src/libcamera/software_isp/meson.build | 1 + - 3 files changed, 770 insertions(+) - create mode 100644 src/libcamera/software_isp/debayer_cpu.cpp - create mode 100644 src/libcamera/software_isp/debayer_cpu.h - -diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp -new file mode 100644 -index 00000000..f932362c ---- /dev/null -+++ b/src/libcamera/software_isp/debayer_cpu.cpp -@@ -0,0 +1,626 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * Copyright (C) 2023, Red Hat Inc. -+ * -+ * Authors: -+ * Hans de Goede <hdegoede@redhat.com> -+ * -+ * debayer_cpu.cpp - CPU based debayering class -+ */ -+ -+#include "debayer_cpu.h" -+ -+#include <math.h> -+#include <stdlib.h> -+#include <time.h> -+ -+#include <libcamera/formats.h> -+ -+#include "libcamera/internal/bayer_format.h" -+#include "libcamera/internal/framebuffer.h" -+#include "libcamera/internal/mapped_framebuffer.h" -+ -+namespace libcamera { -+ -+/** -+ * \class DebayerCpu -+ * \brief Class for debayering on the CPU -+ * -+ * Implementation for CPU based debayering -+ */ -+ -+/** -+ * \brief Constructs a DebayerCpu object. -+ * \param[in] stats Pointer to the stats object to use. -+ */ -+DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats) -+ : stats_(std::move(stats)), gamma_correction_(1.0) -+{ -+#ifdef __x86_64__ -+ enableInputMemcpy_ = false; -+#else -+ enableInputMemcpy_ = true; -+#endif -+ /* Initialize gamma to 1.0 curve */ -+ for (unsigned int i = 0; i < kGammaLookupSize; i++) -+ gamma_[i] = i / (kGammaLookupSize / kRGBLookupSize); -+ -+ for (unsigned int i = 0; i < kMaxLineBuffers; i++) -+ lineBuffers_[i] = nullptr; -+} -+ -+DebayerCpu::~DebayerCpu() -+{ -+ for (unsigned int i = 0; i < kMaxLineBuffers; i++) -+ free(lineBuffers_[i]); -+} -+ -+// RGR -+// GBG -+// RGR -+#define BGGR_BGR888(p, n, div) \ -+ *dst++ = blue_[curr[x] / (div)]; \ -+ *dst++ = green_[(prev[x] + curr[x - p] + curr[x + n] + next[x]) / (4 * (div))]; \ -+ *dst++ = red_[(prev[x - p] + prev[x + n] + next[x - p] + next[x + n]) / (4 * (div))]; \ -+ x++; -+ -+// GBG -+// RGR -+// GBG -+#define GRBG_BGR888(p, n, div) \ -+ *dst++ = blue_[(prev[x] + next[x]) / (2 * (div))]; \ -+ *dst++ = green_[curr[x] / (div)]; \ -+ *dst++ = red_[(curr[x - p] + curr[x + n]) / (2 * (div))]; \ -+ x++; -+ -+// GRG -+// BGB -+// GRG -+#define GBRG_BGR888(p, n, div) \ -+ *dst++ = blue_[(curr[x - p] + curr[x + n]) / (2 * (div))]; \ -+ *dst++ = green_[curr[x] / (div)]; \ -+ *dst++ = red_[(prev[x] + next[x]) / (2 * (div))]; \ -+ x++; -+ -+// BGB -+// GRG -+// BGB -+#define RGGB_BGR888(p, n, div) \ -+ *dst++ = blue_[(prev[x - p] + prev[x + n] + next[x - p] + next[x + n]) / (4 * (div))]; \ -+ *dst++ = green_[(prev[x] + curr[x - p] + curr[x + n] + next[x]) / (4 * (div))]; \ -+ *dst++ = red_[curr[x] / (div)]; \ -+ x++; -+ -+void DebayerCpu::debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ const int width_in_bytes = window_.width * 5 / 4; -+ const uint8_t *prev = (const uint8_t *)src[0]; -+ const uint8_t *curr = (const uint8_t *)src[1]; -+ const uint8_t *next = (const uint8_t *)src[2]; -+ -+ /* -+ * For the first pixel getting a pixel from the previous column uses -+ * x - 2 to skip the 5th byte with least-significant bits for 4 pixels. -+ * Same for last pixel (uses x + 2) and looking at the next column. -+ */ -+ for (int x = 0; x < width_in_bytes;) { -+ /* First pixel */ -+ BGGR_BGR888(2, 1, 1) -+ /* Second pixel BGGR -> GBRG */ -+ GBRG_BGR888(1, 1, 1) -+ /* Same thing for third and fourth pixels */ -+ BGGR_BGR888(1, 1, 1) -+ GBRG_BGR888(1, 2, 1) -+ /* Skip 5th src byte with 4 x 2 least-significant-bits */ -+ x++; -+ } -+} -+ -+void DebayerCpu::debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ const int width_in_bytes = window_.width * 5 / 4; -+ const uint8_t *prev = (const uint8_t *)src[0]; -+ const uint8_t *curr = (const uint8_t *)src[1]; -+ const uint8_t *next = (const uint8_t *)src[2]; -+ -+ for (int x = 0; x < width_in_bytes;) { -+ /* First pixel */ -+ GRBG_BGR888(2, 1, 1) -+ /* Second pixel GRBG -> RGGB */ -+ RGGB_BGR888(1, 1, 1) -+ /* Same thing for third and fourth pixels */ -+ GRBG_BGR888(1, 1, 1) -+ RGGB_BGR888(1, 2, 1) -+ /* Skip 5th src byte with 4 x 2 least-significant-bits */ -+ x++; -+ } -+} -+ -+void DebayerCpu::debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ const int width_in_bytes = window_.width * 5 / 4; -+ const uint8_t *prev = (const uint8_t *)src[0]; -+ const uint8_t *curr = (const uint8_t *)src[1]; -+ const uint8_t *next = (const uint8_t *)src[2]; -+ -+ for (int x = 0; x < width_in_bytes;) { -+ /* Even pixel */ -+ GBRG_BGR888(2, 1, 1) -+ /* Odd pixel GBGR -> BGGR */ -+ BGGR_BGR888(1, 1, 1) -+ /* Same thing for next 2 pixels */ -+ GBRG_BGR888(1, 1, 1) -+ BGGR_BGR888(1, 2, 1) -+ /* Skip 5th src byte with 4 x 2 least-significant-bits */ -+ x++; -+ } -+} -+ -+void DebayerCpu::debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ const int width_in_bytes = window_.width * 5 / 4; -+ const uint8_t *prev = (const uint8_t *)src[0]; -+ const uint8_t *curr = (const uint8_t *)src[1]; -+ const uint8_t *next = (const uint8_t *)src[2]; -+ -+ for (int x = 0; x < width_in_bytes;) { -+ /* Even pixel */ -+ RGGB_BGR888(2, 1, 1) -+ /* Odd pixel RGGB -> GRBG */ -+ GRBG_BGR888(1, 1, 1) -+ /* Same thing for next 2 pixels */ -+ RGGB_BGR888(1, 1, 1) -+ GRBG_BGR888(1, 2, 1) -+ /* Skip 5th src byte with 4 x 2 least-significant-bits */ -+ x++; -+ } -+} -+ -+static bool isStandardBayerOrder(BayerFormat::Order order) -+{ -+ return order == BayerFormat::BGGR || order == BayerFormat::GBRG || -+ order == BayerFormat::GRBG || order == BayerFormat::RGGB; -+} -+ -+/* -+ * Setup the Debayer object according to the passed in parameters. -+ * Return 0 on success, a negative errno value on failure -+ * (unsupported parameters). -+ */ -+int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config) -+{ -+ BayerFormat bayerFormat = -+ BayerFormat::fromPixelFormat(inputFormat); -+ -+ if (bayerFormat.bitDepth == 10 && -+ bayerFormat.packing == BayerFormat::Packing::CSI2 && -+ isStandardBayerOrder(bayerFormat.order)) { -+ config.bpp = 10; -+ config.patternSize.width = 4; /* 5 bytes per *4* pixels */ -+ config.patternSize.height = 2; -+ config.outputFormats = std::vector<PixelFormat>({ formats::RGB888 }); -+ return 0; -+ } -+ -+ LOG(Debayer, Info) -+ << "Unsupported input format " << inputFormat.toString(); -+ return -EINVAL; -+} -+ -+int DebayerCpu::getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config) -+{ -+ if (outputFormat == formats::RGB888) { -+ config.bpp = 24; -+ return 0; -+ } -+ -+ LOG(Debayer, Info) -+ << "Unsupported output format " << outputFormat.toString(); -+ return -EINVAL; -+} -+ -+/* TODO: this ignores outputFormat since there is only 1 supported outputFormat for now */ -+int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, [[maybe_unused]] PixelFormat outputFormat) -+{ -+ BayerFormat bayerFormat = -+ BayerFormat::fromPixelFormat(inputFormat); -+ -+ if (bayerFormat.bitDepth == 10 && -+ bayerFormat.packing == BayerFormat::Packing::CSI2) { -+ switch (bayerFormat.order) { -+ case BayerFormat::BGGR: -+ debayer0_ = &DebayerCpu::debayer10P_BGBG_BGR888; -+ debayer1_ = &DebayerCpu::debayer10P_GRGR_BGR888; -+ return 0; -+ case BayerFormat::GBRG: -+ debayer0_ = &DebayerCpu::debayer10P_GBGB_BGR888; -+ debayer1_ = &DebayerCpu::debayer10P_RGRG_BGR888; -+ return 0; -+ case BayerFormat::GRBG: -+ debayer0_ = &DebayerCpu::debayer10P_GRGR_BGR888; -+ debayer1_ = &DebayerCpu::debayer10P_BGBG_BGR888; -+ return 0; -+ case BayerFormat::RGGB: -+ debayer0_ = &DebayerCpu::debayer10P_RGRG_BGR888; -+ debayer1_ = &DebayerCpu::debayer10P_GBGB_BGR888; -+ return 0; -+ default: -+ break; -+ } -+ } -+ -+ LOG(Debayer, Error) << "Unsupported input output format combination"; -+ return -EINVAL; -+} -+ -+int DebayerCpu::configure(const StreamConfiguration &inputCfg, -+ const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs) -+{ -+ if (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0) -+ return -EINVAL; -+ -+ if (stats_->configure(inputCfg) != 0) -+ return -EINVAL; -+ -+ const Size &stats_pattern_size = stats_->patternSize(); -+ if (inputConfig_.patternSize.width != stats_pattern_size.width || -+ inputConfig_.patternSize.height != stats_pattern_size.height) { -+ LOG(Debayer, Error) -+ << "mismatching stats and debayer pattern sizes for " -+ << inputCfg.pixelFormat.toString(); -+ return -EINVAL; -+ } -+ -+ inputConfig_.stride = inputCfg.stride; -+ -+ if (outputCfgs.size() != 1) { -+ LOG(Debayer, Error) -+ << "Unsupported number of output streams: " -+ << outputCfgs.size(); -+ return -EINVAL; -+ } -+ -+ const StreamConfiguration &outputCfg = outputCfgs[0]; -+ SizeRange outSizeRange = sizes(inputCfg.pixelFormat, inputCfg.size); -+ std::tie(outputConfig_.stride, outputConfig_.frameSize) = -+ strideAndFrameSize(outputCfg.pixelFormat, outputCfg.size); -+ -+ if (!outSizeRange.contains(outputCfg.size) || outputConfig_.stride != outputCfg.stride) { -+ LOG(Debayer, Error) -+ << "Invalid output size/stride: " -+ << "\n " << outputCfg.size << " (" << outSizeRange << ")" -+ << "\n " << outputCfg.stride << " (" << outputConfig_.stride << ")"; -+ return -EINVAL; -+ } -+ -+ if (setDebayerFunctions(inputCfg.pixelFormat, outputCfg.pixelFormat) != 0) -+ return -EINVAL; -+ -+ window_.x = ((inputCfg.size.width - outputCfg.size.width) / 2) & -+ ~(inputConfig_.patternSize.width - 1); -+ window_.y = ((inputCfg.size.height - outputCfg.size.height) / 2) & -+ ~(inputConfig_.patternSize.height - 1); -+ window_.width = outputCfg.size.width; -+ window_.height = outputCfg.size.height; -+ -+ /* Don't pass x,y since process() already adjusts src before passing it */ -+ stats_->setWindow(Rectangle(window_.size())); -+ -+ /* pad with patternSize.Width on both left and right side */ -+ lineBufferPadding_ = inputConfig_.patternSize.width * inputConfig_.bpp / 8; -+ lineBufferLength_ = window_.width * inputConfig_.bpp / 8 + -+ 2 * lineBufferPadding_; -+ for (unsigned int i = 0; -+ i < (inputConfig_.patternSize.height + 1) && enableInputMemcpy_; -+ i++) { -+ free(lineBuffers_[i]); -+ lineBuffers_[i] = (uint8_t *)malloc(lineBufferLength_); -+ if (!lineBuffers_[i]) -+ return -ENOMEM; -+ } -+ -+ measuredFrames_ = 0; -+ frameProcessTime_ = 0; -+ -+ return 0; -+} -+ -+/* -+ * Get width and height at which the bayer-pattern repeats. -+ * Return pattern-size or an empty Size for an unsupported inputFormat. -+ */ -+Size DebayerCpu::patternSize(PixelFormat inputFormat) -+{ -+ DebayerCpu::DebayerInputConfig config; -+ -+ if (getInputConfig(inputFormat, config) != 0) -+ return {}; -+ -+ return config.patternSize; -+} -+ -+std::vector<PixelFormat> DebayerCpu::formats(PixelFormat inputFormat) -+{ -+ DebayerCpu::DebayerInputConfig config; -+ -+ if (getInputConfig(inputFormat, config) != 0) -+ return std::vector<PixelFormat>(); -+ -+ return config.outputFormats; -+} -+ -+std::tuple<unsigned int, unsigned int> -+DebayerCpu::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) -+{ -+ DebayerCpu::DebayerOutputConfig config; -+ -+ if (getOutputConfig(outputFormat, config) != 0) -+ return std::make_tuple(0, 0); -+ -+ /* round up to multiple of 8 for 64 bits alignment */ -+ unsigned int stride = (size.width * config.bpp / 8 + 7) & ~7; -+ -+ return std::make_tuple(stride, stride * size.height); -+} -+ -+void DebayerCpu::setupInputMemcpy(const uint8_t *linePointers[]) -+{ -+ const unsigned int patternHeight = inputConfig_.patternSize.height; -+ -+ if (!enableInputMemcpy_) -+ return; -+ -+ for (unsigned int i = 0; i < patternHeight; i++) { -+ memcpy(lineBuffers_[i], linePointers[i + 1] - lineBufferPadding_, -+ lineBufferLength_); -+ linePointers[i + 1] = lineBuffers_[i] + lineBufferPadding_; -+ } -+ -+ /* Point lineBufferIndex_ to first unused lineBuffer */ -+ lineBufferIndex_ = patternHeight; -+} -+ -+void DebayerCpu::shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src) -+{ -+ const unsigned int patternHeight = inputConfig_.patternSize.height; -+ -+ for (unsigned int i = 0; i < patternHeight; i++) -+ linePointers[i] = linePointers[i + 1]; -+ -+ linePointers[patternHeight] = src + -+ (patternHeight / 2) * (int)inputConfig_.stride; -+} -+ -+void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[]) -+{ -+ const unsigned int patternHeight = inputConfig_.patternSize.height; -+ -+ if (!enableInputMemcpy_) -+ return; -+ -+ memcpy(lineBuffers_[lineBufferIndex_], linePointers[patternHeight] - lineBufferPadding_, -+ lineBufferLength_); -+ linePointers[patternHeight] = lineBuffers_[lineBufferIndex_] + lineBufferPadding_; -+ -+ lineBufferIndex_ = (lineBufferIndex_ + 1) % (patternHeight + 1); -+} -+ -+void DebayerCpu::process2(const uint8_t *src, uint8_t *dst) -+{ -+ unsigned int y_end = window_.y + window_.height; -+ /* Holds [0] previous- [1] current- [2] next-line */ -+ const uint8_t *linePointers[3]; -+ -+ /* Adjust src to top left corner of the window */ -+ src += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8; -+ -+ /* [x] becomes [x - 1] after initial shiftLinePointers() call */ -+ if (window_.y) { -+ linePointers[1] = src - inputConfig_.stride; /* previous-line */ -+ linePointers[2] = src; -+ } else { -+ /* window_.y == 0, use the next line as prev line */ -+ linePointers[1] = src + inputConfig_.stride; -+ linePointers[2] = src; -+ /* Last 2 lines also need special handling */ -+ y_end -= 2; -+ } -+ -+ setupInputMemcpy(linePointers); -+ -+ for (unsigned int y = window_.y; y < y_end; y += 2) { -+ shiftLinePointers(linePointers, src); -+ memcpyNextLine(linePointers); -+ stats_->processLine0(y, linePointers); -+ (this->*debayer0_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ -+ shiftLinePointers(linePointers, src); -+ memcpyNextLine(linePointers); -+ (this->*debayer1_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ } -+ -+ if (window_.y == 0) { -+ shiftLinePointers(linePointers, src); -+ memcpyNextLine(linePointers); -+ stats_->processLine0(y_end, linePointers); -+ (this->*debayer0_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ -+ shiftLinePointers(linePointers, src); -+ /* next line may point outside of src, use prev. */ -+ linePointers[2] = linePointers[0]; -+ (this->*debayer1_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ } -+} -+ -+void DebayerCpu::process4(const uint8_t *src, uint8_t *dst) -+{ -+ const unsigned int y_end = window_.y + window_.height; -+ /* -+ * This holds pointers to [0] 2-lines-up [1] 1-line-up [2] current-line -+ * [3] 1-line-down [4] 2-lines-down. -+ */ -+ const uint8_t *linePointers[5]; -+ -+ /* Adjust src to top left corner of the window */ -+ src += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8; -+ -+ /* [x] becomes [x - 1] after initial shiftLinePointers() call */ -+ linePointers[1] = src - 2 * inputConfig_.stride; -+ linePointers[2] = src - inputConfig_.stride; -+ linePointers[3] = src; -+ linePointers[4] = src + inputConfig_.stride; -+ -+ setupInputMemcpy(linePointers); -+ -+ for (unsigned int y = window_.y; y < y_end; y += 4) { -+ shiftLinePointers(linePointers, src); -+ memcpyNextLine(linePointers); -+ stats_->processLine0(y, linePointers); -+ (this->*debayer0_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ -+ shiftLinePointers(linePointers, src); -+ memcpyNextLine(linePointers); -+ (this->*debayer1_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ -+ shiftLinePointers(linePointers, src); -+ memcpyNextLine(linePointers); -+ stats_->processLine2(y, linePointers); -+ (this->*debayer2_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ -+ shiftLinePointers(linePointers, src); -+ memcpyNextLine(linePointers); -+ (this->*debayer3_)(dst, linePointers); -+ src += inputConfig_.stride; -+ dst += outputConfig_.stride; -+ } -+} -+ -+static inline int64_t timeDiff(timespec &after, timespec &before) -+{ -+ return (after.tv_sec - before.tv_sec) * 1000000000LL + -+ (int64_t)after.tv_nsec - (int64_t)before.tv_nsec; -+} -+ -+void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams params) -+{ -+ timespec frameStartTime; -+ -+ if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure) { -+ frameStartTime = {}; -+ clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime); -+ } -+ -+ /* Apply DebayerParams */ -+ if (params.gamma != gamma_correction_) { -+ for (unsigned int i = 0; i < kGammaLookupSize; i++) -+ gamma_[i] = UINT8_MAX * powf(i / (kGammaLookupSize - 1.0), params.gamma); -+ -+ gamma_correction_ = params.gamma; -+ } -+ -+ for (unsigned int i = 0; i < kRGBLookupSize; i++) { -+ constexpr unsigned int div = -+ kRGBLookupSize * DebayerParams::kGain10 / kGammaLookupSize; -+ unsigned int idx; -+ -+ /* Apply gamma after gain! */ -+ idx = std::min({ i * params.gainR / div, (kGammaLookupSize - 1) }); -+ red_[i] = gamma_[idx]; -+ -+ idx = std::min({ i * params.gainG / div, (kGammaLookupSize - 1) }); -+ green_[i] = gamma_[idx]; -+ -+ idx = std::min({ i * params.gainB / div, (kGammaLookupSize - 1) }); -+ blue_[i] = gamma_[idx]; -+ } -+ -+ /* Copy metadata from the input buffer */ -+ FrameMetadata &metadata = output->_d()->metadata(); -+ metadata.status = input->metadata().status; -+ metadata.sequence = input->metadata().sequence; -+ metadata.timestamp = input->metadata().timestamp; -+ -+ MappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read); -+ MappedFrameBuffer out(output, MappedFrameBuffer::MapFlag::Write); -+ if (!in.isValid() || !out.isValid()) { -+ LOG(Debayer, Error) << "mmap-ing buffer(s) failed"; -+ metadata.status = FrameMetadata::FrameError; -+ return; -+ } -+ -+ stats_->startFrame(); -+ -+ if (inputConfig_.patternSize.height == 2) -+ process2(in.planes()[0].data(), out.planes()[0].data()); -+ else -+ process4(in.planes()[0].data(), out.planes()[0].data()); -+ -+ metadata.planes()[0].bytesused = out.planes()[0].size(); -+ -+ /* Measure before emitting signals */ -+ if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure && -+ ++measuredFrames_ > DebayerCpu::kFramesToSkip) { -+ timespec frameEndTime = {}; -+ clock_gettime(CLOCK_MONOTONIC_RAW, &frameEndTime); -+ frameProcessTime_ += timeDiff(frameEndTime, frameStartTime); -+ if (measuredFrames_ == DebayerCpu::kLastFrameToMeasure) { -+ const unsigned int measuredFrames = DebayerCpu::kLastFrameToMeasure - -+ DebayerCpu::kFramesToSkip; -+ LOG(Debayer, Info) -+ << "Processed " << measuredFrames -+ << " frames in " << frameProcessTime_ / 1000 << "us, " -+ << frameProcessTime_ / (1000 * measuredFrames) -+ << " us/frame"; -+ } -+ } -+ -+ stats_->finishFrame(); -+ outputBufferReady.emit(output); -+ inputBufferReady.emit(input); -+} -+ -+SizeRange DebayerCpu::sizes(PixelFormat inputFormat, const Size &inputSize) -+{ -+ Size pattern_size = patternSize(inputFormat); -+ unsigned int border_height = pattern_size.height; -+ -+ if (pattern_size.isNull()) -+ return {}; -+ -+ /* No need for top/bottom border with a pattern height of 2 */ -+ if (pattern_size.height == 2) -+ border_height = 0; -+ -+ /* -+ * For debayer interpolation a border is kept around the entire image -+ * and the minimum output size is pattern-height x pattern-width. -+ */ -+ if (inputSize.width < (3 * pattern_size.width) || -+ inputSize.height < (2 * border_height + pattern_size.height)) { -+ LOG(Debayer, Warning) -+ << "Input format size too small: " << inputSize.toString(); -+ return {}; -+ } -+ -+ return SizeRange(Size(pattern_size.width, pattern_size.height), -+ Size((inputSize.width - 2 * pattern_size.width) & ~(pattern_size.width - 1), -+ (inputSize.height - 2 * border_height) & ~(pattern_size.height - 1)), -+ pattern_size.width, pattern_size.height); -+} -+ -+} /* namespace libcamera */ -diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h -new file mode 100644 -index 00000000..8a51ed85 ---- /dev/null -+++ b/src/libcamera/software_isp/debayer_cpu.h -@@ -0,0 +1,143 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * Copyright (C) 2023, Red Hat Inc. -+ * -+ * Authors: -+ * Hans de Goede <hdegoede@redhat.com> -+ * -+ * debayer_cpu.h - CPU based debayering header -+ */ -+ -+#pragma once -+ -+#include <memory> -+#include <stdint.h> -+#include <vector> -+ -+#include <libcamera/base/object.h> -+ -+#include "debayer.h" -+#include "swstats_cpu.h" -+ -+namespace libcamera { -+ -+class DebayerCpu : public Debayer, public Object -+{ -+public: -+ DebayerCpu(std::unique_ptr<SwStatsCpu> stats); -+ ~DebayerCpu(); -+ -+ int configure(const StreamConfiguration &inputCfg, -+ const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs); -+ Size patternSize(PixelFormat inputFormat); -+ std::vector<PixelFormat> formats(PixelFormat input); -+ std::tuple<unsigned int, unsigned int> -+ strideAndFrameSize(const PixelFormat &outputFormat, const Size &size); -+ void process(FrameBuffer *input, FrameBuffer *output, DebayerParams params); -+ SizeRange sizes(PixelFormat inputFormat, const Size &inputSize); -+ -+ /** -+ * \brief Get the file descriptor for the statistics. -+ * -+ * \return the file descriptor pointing to the statistics. -+ */ -+ const SharedFD &getStatsFD() { return stats_->getStatsFD(); } -+ -+ /** -+ * \brief Get the output frame size. -+ * -+ * \return The output frame size. -+ */ -+ unsigned int frameSize() { return outputConfig_.frameSize; } -+ -+private: -+ /** -+ * \brief Called to debayer 1 line of Bayer input data to output format -+ * \param[out] dst Pointer to the start of the output line to write -+ * \param[in] src The input data -+ * -+ * Input data is an array of (patternSize_.height + 1) src -+ * pointers each pointing to a line in the Bayer source. The middle -+ * element of the array will point to the actual line being processed. -+ * Earlier element(s) will point to the previous line(s) and later -+ * element(s) to the next line(s). -+ * -+ * These functions take an array of src pointers, rather than -+ * a single src pointer + a stride for the source, so that when the src -+ * is slow uncached memory it can be copied to faster memory before -+ * debayering. Debayering a standard 2x2 Bayer pattern requires access -+ * to the previous and next src lines for interpolating the missing -+ * colors. To allow copying the src lines only once 3 temporary buffers -+ * each holding a single line are used, re-using the oldest buffer for -+ * the next line and the pointers are swizzled so that: -+ * src[0] = previous-line, src[1] = currrent-line, src[2] = next-line. -+ * This way the 3 pointers passed to the debayer functions form -+ * a sliding window over the src avoiding the need to copy each -+ * line more than once. -+ * -+ * Similarly for bayer patterns which repeat every 4 lines, 5 src -+ * pointers are passed holding: src[0] = 2-lines-up, src[1] = 1-line-up -+ * src[2] = current-line, src[3] = 1-line-down, src[4] = 2-lines-down. -+ */ -+ using debayerFn = void (DebayerCpu::*)(uint8_t *dst, const uint8_t *src[]); -+ -+ /* CSI-2 packed 10-bit raw bayer format (all the 4 orders) */ -+ void debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]); -+ void debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]); -+ void debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src[]); -+ void debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]); -+ -+ struct DebayerInputConfig { -+ Size patternSize; -+ unsigned int bpp; /* Memory used per pixel, not precision */ -+ unsigned int stride; -+ std::vector<PixelFormat> outputFormats; -+ }; -+ -+ struct DebayerOutputConfig { -+ unsigned int bpp; /* Memory used per pixel, not precision */ -+ unsigned int stride; -+ unsigned int frameSize; -+ }; -+ -+ int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config); -+ int getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config); -+ int setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputFormat); -+ void setupInputMemcpy(const uint8_t *linePointers[]); -+ void shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src); -+ void memcpyNextLine(const uint8_t *linePointers[]); -+ void process2(const uint8_t *src, uint8_t *dst); -+ void process4(const uint8_t *src, uint8_t *dst); -+ -+ static constexpr unsigned int kGammaLookupSize = 1024; -+ static constexpr unsigned int kRGBLookupSize = 256; -+ /* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */ -+ static constexpr unsigned int kMaxLineBuffers = 5; -+ -+ std::array<uint8_t, kGammaLookupSize> gamma_; -+ std::array<uint8_t, kRGBLookupSize> red_; -+ std::array<uint8_t, kRGBLookupSize> green_; -+ std::array<uint8_t, kRGBLookupSize> blue_; -+ debayerFn debayer0_; -+ debayerFn debayer1_; -+ debayerFn debayer2_; -+ debayerFn debayer3_; -+ Rectangle window_; -+ DebayerInputConfig inputConfig_; -+ DebayerOutputConfig outputConfig_; -+ std::unique_ptr<SwStatsCpu> stats_; -+ uint8_t *lineBuffers_[kMaxLineBuffers]; -+ unsigned int lineBufferLength_; -+ unsigned int lineBufferPadding_; -+ unsigned int lineBufferIndex_; -+ bool enableInputMemcpy_; -+ float gamma_correction_; -+ unsigned int measuredFrames_; -+ int64_t frameProcessTime_; -+ /* Skip 30 frames for things to stabilize then measure 30 frames */ -+ static constexpr unsigned int kFramesToSkip = 30; -+ static constexpr unsigned int kLastFrameToMeasure = 60; -+}; -+ -+} /* namespace libcamera */ -diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build -index 62095f61..71b46539 100644 ---- a/src/libcamera/software_isp/meson.build -+++ b/src/libcamera/software_isp/meson.build -@@ -9,5 +9,6 @@ endif - - libcamera_sources += files([ - 'debayer.cpp', -+ 'debayer_cpu.cpp', - 'swstats_cpu.cpp', - ]) --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0009-libcamera-ipa-add-Soft-IPA.patch b/users/flokli/ipu6-softisp/libcamera/0009-libcamera-ipa-add-Soft-IPA.patch deleted file mode 100644 index 40f9403ba984..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0009-libcamera-ipa-add-Soft-IPA.patch +++ /dev/null @@ -1,506 +0,0 @@ -From 5261c801d8425fa82bcbd3da0199d06153eb5bd7 Mon Sep 17 00:00:00 2001 -From: Andrey Konovalov <andrey.konovalov@linaro.org> -Date: Mon, 11 Mar 2024 15:15:13 +0100 -Subject: [PATCH 09/21] libcamera: ipa: add Soft IPA - -Define the Soft IPA main and event interfaces, add the Soft IPA -implementation. - -The current src/ipa/meson.build assumes the IPA name to match the -pipeline name. For this reason "-Dipas=simple" is used for the -Soft IPA module. - -Auto exposure/gain and AWB implementation by Dennis, Toon and Martti. - -Auto exposure/gain targets a Mean Sample Value of 2.5 following -the MSV calculation algorithm from: -https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Co-developed-by: Dennis Bonke <admin@dennisbonke.com> -Signed-off-by: Dennis Bonke <admin@dennisbonke.com> -Co-developed-by: Marttico <g.martti@gmail.com> -Signed-off-by: Marttico <g.martti@gmail.com> -Co-developed-by: Toon Langendam <t.langendam@gmail.com> -Signed-off-by: Toon Langendam <t.langendam@gmail.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - Documentation/Doxyfile.in | 1 + - include/libcamera/ipa/meson.build | 1 + - include/libcamera/ipa/soft.mojom | 28 +++ - meson_options.txt | 2 +- - src/ipa/simple/data/meson.build | 9 + - src/ipa/simple/data/soft.conf | 3 + - src/ipa/simple/meson.build | 25 +++ - src/ipa/simple/soft_simple.cpp | 326 ++++++++++++++++++++++++++++++ - 8 files changed, 394 insertions(+), 1 deletion(-) - create mode 100644 include/libcamera/ipa/soft.mojom - create mode 100644 src/ipa/simple/data/meson.build - create mode 100644 src/ipa/simple/data/soft.conf - create mode 100644 src/ipa/simple/meson.build - create mode 100644 src/ipa/simple/soft_simple.cpp - -diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in -index a86ea6c1..2be8d47b 100644 ---- a/Documentation/Doxyfile.in -+++ b/Documentation/Doxyfile.in -@@ -44,6 +44,7 @@ EXCLUDE = @TOP_SRCDIR@/include/libcamera/base/span.h \ - @TOP_SRCDIR@/src/libcamera/pipeline/ \ - @TOP_SRCDIR@/src/libcamera/tracepoints.cpp \ - @TOP_BUILDDIR@/include/libcamera/internal/tracepoints.h \ -+ @TOP_BUILDDIR@/include/libcamera/ipa/soft_ipa_interface.h \ - @TOP_BUILDDIR@/src/libcamera/proxy/ - - EXCLUDE_PATTERNS = @TOP_BUILDDIR@/include/libcamera/ipa/*_serializer.h \ -diff --git a/include/libcamera/ipa/meson.build b/include/libcamera/ipa/meson.build -index f3b4881c..3352d08f 100644 ---- a/include/libcamera/ipa/meson.build -+++ b/include/libcamera/ipa/meson.build -@@ -65,6 +65,7 @@ pipeline_ipa_mojom_mapping = { - 'ipu3': 'ipu3.mojom', - 'rkisp1': 'rkisp1.mojom', - 'rpi/vc4': 'raspberrypi.mojom', -+ 'simple': 'soft.mojom', - 'vimc': 'vimc.mojom', - } - -diff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom -new file mode 100644 -index 00000000..c249bd75 ---- /dev/null -+++ b/include/libcamera/ipa/soft.mojom -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+ -+/* -+ * \todo Document the interface and remove the related EXCLUDE_PATTERNS entry. -+ */ -+ -+module ipa.soft; -+ -+import "include/libcamera/ipa/core.mojom"; -+ -+interface IPASoftInterface { -+ init(libcamera.IPASettings settings, -+ libcamera.SharedFD fdStats, -+ libcamera.SharedFD fdParams, -+ libcamera.ControlInfoMap sensorCtrlInfoMap) -+ => (int32 ret); -+ start() => (int32 ret); -+ stop(); -+ configure(libcamera.ControlInfoMap sensorCtrlInfoMap) -+ => (int32 ret); -+ -+ [async] processStats(libcamera.ControlList sensorControls); -+}; -+ -+interface IPASoftEventInterface { -+ setSensorControls(libcamera.ControlList sensorControls); -+ setIspParams(int32 dummy); -+}; -diff --git a/meson_options.txt b/meson_options.txt -index 5fdc7be8..94372e47 100644 ---- a/meson_options.txt -+++ b/meson_options.txt -@@ -27,7 +27,7 @@ option('gstreamer', - - option('ipas', - type : 'array', -- choices : ['ipu3', 'rkisp1', 'rpi/vc4', 'vimc'], -+ choices : ['ipu3', 'rkisp1', 'rpi/vc4', 'simple', 'vimc'], - description : 'Select which IPA modules to build') - - option('lc-compliance', -diff --git a/src/ipa/simple/data/meson.build b/src/ipa/simple/data/meson.build -new file mode 100644 -index 00000000..33548cc6 ---- /dev/null -+++ b/src/ipa/simple/data/meson.build -@@ -0,0 +1,9 @@ -+# SPDX-License-Identifier: CC0-1.0 -+ -+conf_files = files([ -+ 'soft.conf', -+]) -+ -+install_data(conf_files, -+ install_dir : ipa_data_dir / 'soft', -+ install_tag : 'runtime') -diff --git a/src/ipa/simple/data/soft.conf b/src/ipa/simple/data/soft.conf -new file mode 100644 -index 00000000..0c70e7c0 ---- /dev/null -+++ b/src/ipa/simple/data/soft.conf -@@ -0,0 +1,3 @@ -+# SPDX-License-Identifier: LGPL-2.1-or-later -+# -+# Dummy configuration file for the soft IPA. -diff --git a/src/ipa/simple/meson.build b/src/ipa/simple/meson.build -new file mode 100644 -index 00000000..3e863db7 ---- /dev/null -+++ b/src/ipa/simple/meson.build -@@ -0,0 +1,25 @@ -+# SPDX-License-Identifier: CC0-1.0 -+ -+ipa_name = 'ipa_soft_simple' -+ -+mod = shared_module(ipa_name, -+ ['soft_simple.cpp', libcamera_generated_ipa_headers], -+ name_prefix : '', -+ include_directories : [ipa_includes, libipa_includes], -+ dependencies : libcamera_private, -+ link_with : libipa, -+ install : true, -+ install_dir : ipa_install_dir) -+ -+if ipa_sign_module -+ custom_target(ipa_name + '.so.sign', -+ input : mod, -+ output : ipa_name + '.so.sign', -+ command : [ipa_sign, ipa_priv_key, '@INPUT@', '@OUTPUT@'], -+ install : false, -+ build_by_default : true) -+endif -+ -+subdir('data') -+ -+ipa_names += ipa_name -diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp -new file mode 100644 -index 00000000..312df4ba ---- /dev/null -+++ b/src/ipa/simple/soft_simple.cpp -@@ -0,0 +1,326 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * -+ * soft_simple.cpp - Simple Software Image Processing Algorithm module -+ */ -+ -+#include <sys/mman.h> -+ -+#include <libcamera/base/file.h> -+#include <libcamera/base/log.h> -+#include <libcamera/base/shared_fd.h> -+ -+#include <libcamera/control_ids.h> -+#include <libcamera/controls.h> -+ -+#include <libcamera/ipa/ipa_interface.h> -+#include <libcamera/ipa/ipa_module_info.h> -+#include <libcamera/ipa/soft_ipa_interface.h> -+ -+#include "libcamera/internal/camera_sensor.h" -+#include "libcamera/internal/software_isp/debayer_params.h" -+#include "libcamera/internal/software_isp/swisp_stats.h" -+ -+namespace libcamera { -+ -+LOG_DEFINE_CATEGORY(IPASoft) -+ -+namespace ipa::soft { -+ -+class IPASoftSimple : public ipa::soft::IPASoftInterface -+{ -+public: -+ IPASoftSimple() -+ : params_(static_cast<DebayerParams *>(MAP_FAILED)), -+ stats_(static_cast<SwIspStats *>(MAP_FAILED)), ignore_updates_(0) -+ { -+ } -+ -+ ~IPASoftSimple() -+ { -+ if (stats_ != MAP_FAILED) -+ munmap(stats_, sizeof(SwIspStats)); -+ if (params_ != MAP_FAILED) -+ munmap(params_, sizeof(DebayerParams)); -+ } -+ -+ int init(const IPASettings &settings, -+ const SharedFD &fdStats, -+ const SharedFD &fdParams, -+ const ControlInfoMap &sensorInfoMap) override; -+ int configure(const ControlInfoMap &sensorInfoMap) override; -+ -+ int start() override; -+ void stop() override; -+ -+ void processStats(const ControlList &sensorControls) override; -+ -+private: -+ void updateExposure(double exposureMSV); -+ -+ SharedFD fdStats_; -+ SharedFD fdParams_; -+ DebayerParams *params_; -+ SwIspStats *stats_; -+ -+ int32_t exposure_min_, exposure_max_; -+ int32_t again_min_, again_max_; -+ int32_t again_, exposure_; -+ unsigned int ignore_updates_; -+}; -+ -+int IPASoftSimple::init([[maybe_unused]] const IPASettings &settings, -+ const SharedFD &fdStats, -+ const SharedFD &fdParams, -+ const ControlInfoMap &sensorInfoMap) -+{ -+ fdStats_ = fdStats; -+ if (!fdStats_.isValid()) { -+ LOG(IPASoft, Error) << "Invalid Statistics handle"; -+ return -ENODEV; -+ } -+ -+ fdParams_ = fdParams; -+ if (!fdParams_.isValid()) { -+ LOG(IPASoft, Error) << "Invalid Parameters handle"; -+ return -ENODEV; -+ } -+ -+ params_ = static_cast<DebayerParams *>(mmap(nullptr, sizeof(DebayerParams), -+ PROT_WRITE, MAP_SHARED, -+ fdParams_.get(), 0)); -+ if (params_ == MAP_FAILED) { -+ LOG(IPASoft, Error) << "Unable to map Parameters"; -+ return -errno; -+ } -+ -+ stats_ = static_cast<SwIspStats *>(mmap(nullptr, sizeof(SwIspStats), -+ PROT_READ, MAP_SHARED, -+ fdStats_.get(), 0)); -+ if (stats_ == MAP_FAILED) { -+ LOG(IPASoft, Error) << "Unable to map Statistics"; -+ return -errno; -+ } -+ -+ if (sensorInfoMap.find(V4L2_CID_EXPOSURE) == sensorInfoMap.end()) { -+ LOG(IPASoft, Error) << "Don't have exposure control"; -+ return -EINVAL; -+ } -+ -+ if (sensorInfoMap.find(V4L2_CID_ANALOGUE_GAIN) == sensorInfoMap.end()) { -+ LOG(IPASoft, Error) << "Don't have gain control"; -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+int IPASoftSimple::configure(const ControlInfoMap &sensorInfoMap) -+{ -+ const ControlInfo &exposure_info = sensorInfoMap.find(V4L2_CID_EXPOSURE)->second; -+ const ControlInfo &gain_info = sensorInfoMap.find(V4L2_CID_ANALOGUE_GAIN)->second; -+ -+ exposure_min_ = exposure_info.min().get<int32_t>(); -+ exposure_max_ = exposure_info.max().get<int32_t>(); -+ if (!exposure_min_) { -+ LOG(IPASoft, Warning) << "Minimum exposure is zero, that can't be linear"; -+ exposure_min_ = 1; -+ } -+ -+ again_min_ = gain_info.min().get<int32_t>(); -+ again_max_ = gain_info.max().get<int32_t>(); -+ /* -+ * The camera sensor gain (g) is usually not equal to the value written -+ * into the gain register (x). But the way how the AGC algorithm changes -+ * the gain value to make the total exposure closer to the optimum assumes -+ * that g(x) is not too far from linear function. If the minimal gain is 0, -+ * the g(x) is likely to be far from the linear, like g(x) = a / (b * x + c). -+ * To avoid unexpected changes to the gain by the AGC algorithm (abrupt near -+ * one edge, and very small near the other) we limit the range of the gain -+ * values used. -+ */ -+ if (!again_min_) { -+ LOG(IPASoft, Warning) << "Minimum gain is zero, that can't be linear"; -+ again_min_ = std::min(100, again_min_ / 2 + again_max_ / 2); -+ } -+ -+ LOG(IPASoft, Info) << "Exposure " << exposure_min_ << "-" << exposure_max_ -+ << ", gain " << again_min_ << "-" << again_max_; -+ -+ return 0; -+} -+ -+int IPASoftSimple::start() -+{ -+ return 0; -+} -+ -+void IPASoftSimple::stop() -+{ -+} -+ -+/* -+ * The number of bins to use for the optimal exposure calculations. -+ */ -+static constexpr unsigned int kExposureBinsCount = 5; -+/* -+ * The exposure is optimal when the mean sample value of the histogram is -+ * in the middle of the range. -+ */ -+static constexpr float kExposureOptimal = kExposureBinsCount / 2.0; -+/* -+ * The below value implements the hysteresis for the exposure adjustment. -+ * It is small enough to have the exposure close to the optimal, and is big -+ * enough to prevent the exposure from wobbling around the optimal value. -+ */ -+static constexpr float kExposureSatisfactory = 0.2; -+ -+void IPASoftSimple::processStats(const ControlList &sensorControls) -+{ -+ /* -+ * Calculate red and blue gains for AWB. -+ * Clamp max gain at 4.0, this also avoids 0 division. -+ */ -+ if (stats_->sumR_ <= stats_->sumG_ / 4) -+ params_->gainR = 1024; -+ else -+ params_->gainR = 256 * stats_->sumG_ / stats_->sumR_; -+ -+ if (stats_->sumB_ <= stats_->sumG_ / 4) -+ params_->gainB = 1024; -+ else -+ params_->gainB = 256 * stats_->sumG_ / stats_->sumB_; -+ -+ /* Green gain and gamma values are fixed */ -+ params_->gainG = 256; -+ params_->gamma = 0.5; -+ -+ setIspParams.emit(0); -+ -+ /* -+ * AE / AGC, use 2 frames delay to make sure that the exposure and -+ * the gain set have applied to the camera sensor. -+ */ -+ if (ignore_updates_ > 0) { -+ --ignore_updates_; -+ return; -+ } -+ -+ /* -+ * Calculate Mean Sample Value (MSV) according to formula from: -+ * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf -+ */ -+ constexpr unsigned int yHistValsPerBin = -+ SwIspStats::kYHistogramSize / kExposureBinsCount; -+ constexpr unsigned int yHistValsPerBinMod = -+ SwIspStats::kYHistogramSize / -+ (SwIspStats::kYHistogramSize % kExposureBinsCount + 1); -+ int ExposureBins[kExposureBinsCount] = {}; -+ unsigned int denom = 0; -+ unsigned int num = 0; -+ -+ for (unsigned int i = 0; i < SwIspStats::kYHistogramSize; i++) { -+ unsigned int idx = (i - (i / yHistValsPerBinMod)) / yHistValsPerBin; -+ ExposureBins[idx] += stats_->yHistogram[i]; -+ } -+ -+ for (unsigned int i = 0; i < kExposureBinsCount; i++) { -+ LOG(IPASoft, Debug) << i << ": " << ExposureBins[i]; -+ denom += ExposureBins[i]; -+ num += ExposureBins[i] * (i + 1); -+ } -+ -+ float exposureMSV = (float)num / denom; -+ -+ /* sanity check */ -+ if (!sensorControls.contains(V4L2_CID_EXPOSURE) || -+ !sensorControls.contains(V4L2_CID_ANALOGUE_GAIN)) { -+ LOG(IPASoft, Error) << "Control(s) missing"; -+ return; -+ } -+ -+ ControlList ctrls(sensorControls); -+ -+ exposure_ = ctrls.get(V4L2_CID_EXPOSURE).get<int32_t>(); -+ again_ = ctrls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>(); -+ -+ updateExposure(exposureMSV); -+ -+ ctrls.set(V4L2_CID_EXPOSURE, exposure_); -+ ctrls.set(V4L2_CID_ANALOGUE_GAIN, again_); -+ -+ ignore_updates_ = 2; -+ -+ setSensorControls.emit(ctrls); -+ -+ LOG(IPASoft, Debug) << "exposureMSV " << exposureMSV -+ << " exp " << exposure_ << " again " << again_ -+ << " gain R/B " << params_->gainR << "/" << params_->gainB; -+} -+ -+void IPASoftSimple::updateExposure(double exposureMSV) -+{ -+ /* DENOMINATOR of 10 gives ~10% increment/decrement; DENOMINATOR of 5 - about ~20% */ -+ static constexpr uint8_t kExpDenominator = 10; -+ static constexpr uint8_t kExpNumeratorUp = kExpDenominator + 1; -+ static constexpr uint8_t kExpNumeratorDown = kExpDenominator - 1; -+ -+ int next; -+ -+ if (exposureMSV < kExposureOptimal - kExposureSatisfactory) { -+ next = exposure_ * kExpNumeratorUp / kExpDenominator; -+ if (next - exposure_ < 1) -+ exposure_ += 1; -+ else -+ exposure_ = next; -+ if (exposure_ >= exposure_max_) { -+ next = again_ * kExpNumeratorUp / kExpDenominator; -+ if (next - again_ < 1) -+ again_ += 1; -+ else -+ again_ = next; -+ } -+ } -+ -+ if (exposureMSV > kExposureOptimal + kExposureSatisfactory) { -+ if (exposure_ == exposure_max_ && again_ != again_min_) { -+ next = again_ * kExpNumeratorDown / kExpDenominator; -+ if (again_ - next < 1) -+ again_ -= 1; -+ else -+ again_ = next; -+ } else { -+ next = exposure_ * kExpNumeratorDown / kExpDenominator; -+ if (exposure_ - next < 1) -+ exposure_ -= 1; -+ else -+ exposure_ = next; -+ } -+ } -+ -+ exposure_ = std::clamp(exposure_, exposure_min_, exposure_max_); -+ again_ = std::clamp(again_, again_min_, again_max_); -+} -+ -+} /* namespace ipa::soft */ -+ -+/* -+ * External IPA module interface -+ */ -+extern "C" { -+const struct IPAModuleInfo ipaModuleInfo = { -+ IPA_MODULE_API_VERSION, -+ 0, -+ "SimplePipelineHandler", -+ "simple", -+}; -+ -+IPAInterface *ipaCreate() -+{ -+ return new ipa::soft::IPASoftSimple(); -+} -+ -+} /* extern "C" */ -+ -+} /* namespace libcamera */ --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0010-libcamera-introduce-SoftwareIsp.patch b/users/flokli/ipu6-softisp/libcamera/0010-libcamera-introduce-SoftwareIsp.patch deleted file mode 100644 index 9f2d66c2f8b6..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0010-libcamera-introduce-SoftwareIsp.patch +++ /dev/null @@ -1,507 +0,0 @@ -From ad41ea12fe4b8ca0ace20781c775a63ed0d66f4c Mon Sep 17 00:00:00 2001 -From: Andrey Konovalov <andrey.konovalov@linaro.org> -Date: Mon, 11 Mar 2024 15:15:14 +0100 -Subject: [PATCH 10/21] libcamera: introduce SoftwareIsp - -Doxygen documentation by Dennis Bonke. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Co-developed-by: Dennis Bonke <admin@dennisbonke.com> -Signed-off-by: Dennis Bonke <admin@dennisbonke.com> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - .../internal/software_isp/meson.build | 1 + - .../internal/software_isp/software_isp.h | 98 +++++ - src/libcamera/software_isp/meson.build | 1 + - src/libcamera/software_isp/software_isp.cpp | 349 ++++++++++++++++++ - 4 files changed, 449 insertions(+) - create mode 100644 include/libcamera/internal/software_isp/software_isp.h - create mode 100644 src/libcamera/software_isp/software_isp.cpp - -diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build -index a620e16d..508ddddc 100644 ---- a/include/libcamera/internal/software_isp/meson.build -+++ b/include/libcamera/internal/software_isp/meson.build -@@ -2,5 +2,6 @@ - - libcamera_internal_headers += files([ - 'debayer_params.h', -+ 'software_isp.h', - 'swisp_stats.h', - ]) -diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h -new file mode 100644 -index 00000000..8d25e979 ---- /dev/null -+++ b/include/libcamera/internal/software_isp/software_isp.h -@@ -0,0 +1,98 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * -+ * software_isp.h - Simple software ISP implementation -+ */ -+ -+#pragma once -+ -+#include <functional> -+#include <initializer_list> -+#include <map> -+#include <memory> -+#include <string> -+#include <tuple> -+#include <vector> -+ -+#include <libcamera/base/class.h> -+#include <libcamera/base/log.h> -+#include <libcamera/base/signal.h> -+#include <libcamera/base/thread.h> -+ -+#include <libcamera/geometry.h> -+#include <libcamera/pixel_format.h> -+ -+#include <libcamera/ipa/soft_ipa_interface.h> -+#include <libcamera/ipa/soft_ipa_proxy.h> -+ -+#include "libcamera/internal/dma_heaps.h" -+#include "libcamera/internal/pipeline_handler.h" -+#include "libcamera/internal/shared_mem_object.h" -+#include "libcamera/internal/software_isp/debayer_params.h" -+ -+namespace libcamera { -+ -+class DebayerCpu; -+class FrameBuffer; -+class PixelFormat; -+struct StreamConfiguration; -+ -+LOG_DECLARE_CATEGORY(SoftwareIsp) -+ -+class SoftwareIsp -+{ -+public: -+ SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls); -+ ~SoftwareIsp(); -+ -+ int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; } -+ -+ bool isValid() const; -+ -+ std::vector<PixelFormat> formats(PixelFormat input); -+ -+ SizeRange sizes(PixelFormat inputFormat, const Size &inputSize); -+ -+ std::tuple<unsigned int, unsigned int> -+ strideAndFrameSize(const PixelFormat &outputFormat, const Size &size); -+ -+ int configure(const StreamConfiguration &inputCfg, -+ const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs, -+ const ControlInfoMap &sensorControls); -+ -+ int exportBuffers(unsigned int output, unsigned int count, -+ std::vector<std::unique_ptr<FrameBuffer>> *buffers); -+ -+ void processStats(const ControlList &sensorControls); -+ -+ int start(); -+ void stop(); -+ -+ int queueBuffers(FrameBuffer *input, -+ const std::map<unsigned int, FrameBuffer *> &outputs); -+ -+ void process(FrameBuffer *input, FrameBuffer *output); -+ -+ Signal<FrameBuffer *> inputBufferReady; -+ Signal<FrameBuffer *> outputBufferReady; -+ Signal<int> ispStatsReady; -+ Signal<const ControlList &> setSensorControls; -+ -+private: -+ void saveIspParams(int dummy); -+ void setSensorCtrls(const ControlList &sensorControls); -+ void statsReady(int dummy); -+ void inputReady(FrameBuffer *input); -+ void outputReady(FrameBuffer *output); -+ -+ std::unique_ptr<DebayerCpu> debayer_; -+ Thread ispWorkerThread_; -+ SharedMemObject<DebayerParams> sharedParams_; -+ DebayerParams debayerParams_; -+ DmaHeap dmaHeap_; -+ -+ std::unique_ptr<ipa::soft::IPAProxySoft> ipa_; -+}; -+ -+} /* namespace libcamera */ -diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build -index 71b46539..e9266e54 100644 ---- a/src/libcamera/software_isp/meson.build -+++ b/src/libcamera/software_isp/meson.build -@@ -10,5 +10,6 @@ endif - libcamera_sources += files([ - 'debayer.cpp', - 'debayer_cpu.cpp', -+ 'software_isp.cpp', - 'swstats_cpu.cpp', - ]) -diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp -new file mode 100644 -index 00000000..388b4496 ---- /dev/null -+++ b/src/libcamera/software_isp/software_isp.cpp -@@ -0,0 +1,349 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2023, Linaro Ltd -+ * -+ * software_isp.cpp - Simple software ISP implementation -+ */ -+ -+#include "libcamera/internal/software_isp/software_isp.h" -+ -+#include <sys/mman.h> -+#include <sys/types.h> -+#include <unistd.h> -+ -+#include <libcamera/formats.h> -+#include <libcamera/stream.h> -+ -+#include "libcamera/internal/bayer_format.h" -+#include "libcamera/internal/framebuffer.h" -+#include "libcamera/internal/ipa_manager.h" -+#include "libcamera/internal/mapped_framebuffer.h" -+ -+#include "debayer_cpu.h" -+ -+/** -+ * \file software_isp.cpp -+ * \brief Simple software ISP implementation -+ */ -+ -+namespace libcamera { -+ -+LOG_DEFINE_CATEGORY(SoftwareIsp) -+ -+/** -+ * \class SoftwareIsp -+ * \brief Class for the Software ISP -+ */ -+ -+/** -+ * \var SoftwareIsp::inputBufferReady -+ * \brief A signal emitted when the input frame buffer completes -+ */ -+ -+/** -+ * \var SoftwareIsp::outputBufferReady -+ * \brief A signal emitted when the output frame buffer completes -+ */ -+ -+/** -+ * \var SoftwareIsp::ispStatsReady -+ * \brief A signal emitted when the statistics for IPA are ready -+ * -+ * The int parameter isn't actually used. -+ */ -+ -+/** -+ * \var SoftwareIsp::setSensorControls -+ * \brief A signal emitted when the values to write to the sensor controls are ready -+ */ -+ -+/** -+ * \brief Constructs SoftwareIsp object -+ * \param[in] pipe The pipeline handler in use -+ * \param[in] sensorControls ControlInfoMap describing the controls supported by the sensor -+ */ -+SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls) -+ : debayer_(nullptr), -+ debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10, DebayerParams::kGain10, 0.5f }, -+ dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System) -+{ -+ if (!dmaHeap_.isValid()) { -+ LOG(SoftwareIsp, Error) << "Failed to create DmaHeap object"; -+ return; -+ } -+ -+ sharedParams_ = SharedMemObject<DebayerParams>("softIsp_params"); -+ if (!sharedParams_) { -+ LOG(SoftwareIsp, Error) << "Failed to create shared memory for parameters"; -+ return; -+ } -+ -+ auto stats = std::make_unique<SwStatsCpu>(); -+ if (!stats->isValid()) { -+ LOG(SoftwareIsp, Error) << "Failed to create SwStatsCpu object"; -+ return; -+ } -+ stats->statsReady.connect(this, &SoftwareIsp::statsReady); -+ -+ debayer_ = std::make_unique<DebayerCpu>(std::move(stats)); -+ debayer_->inputBufferReady.connect(this, &SoftwareIsp::inputReady); -+ debayer_->outputBufferReady.connect(this, &SoftwareIsp::outputReady); -+ -+ ipa_ = IPAManager::createIPA<ipa::soft::IPAProxySoft>(pipe, 0, 0); -+ if (!ipa_) { -+ LOG(SoftwareIsp, Error) -+ << "Creating IPA for software ISP failed"; -+ debayer_.reset(); -+ return; -+ } -+ -+ int ret = ipa_->init(IPASettings{ "No cfg file", "No sensor model" }, -+ debayer_->getStatsFD(), -+ sharedParams_.fd(), -+ sensorControls); -+ if (ret) { -+ LOG(SoftwareIsp, Error) << "IPA init failed"; -+ debayer_.reset(); -+ return; -+ } -+ -+ ipa_->setIspParams.connect(this, &SoftwareIsp::saveIspParams); -+ ipa_->setSensorControls.connect(this, &SoftwareIsp::setSensorCtrls); -+ -+ debayer_->moveToThread(&ispWorkerThread_); -+} -+ -+SoftwareIsp::~SoftwareIsp() -+{ -+ /* make sure to destroy the DebayerCpu before the ispWorkerThread_ is gone */ -+ debayer_.reset(); -+} -+ -+/** -+ * \fn int SoftwareIsp::loadConfiguration([[maybe_unused]] const std::string &filename) -+ * \brief Load a configuration from a file -+ * \param[in] filename The file to load the configuration data from -+ * -+ * Currently is a stub doing nothing and always returning "success". -+ * -+ * \return 0 on success -+ */ -+ -+/** -+ * \brief Process the statistics gathered -+ * \param[in] sensorControls The sensor controls -+ * -+ * Requests the IPA to calculate new parameters for ISP and new control -+ * values for the sensor. -+ */ -+void SoftwareIsp::processStats(const ControlList &sensorControls) -+{ -+ ASSERT(ipa_); -+ ipa_->processStats(sensorControls); -+} -+ -+/** -+ * \brief Check the validity of Software Isp object -+ * \return True if Software Isp is valid, false otherwise -+ */ -+bool SoftwareIsp::isValid() const -+{ -+ return !!debayer_; -+} -+ -+/** -+ * \brief Get the output formats supported for the given input format -+ * \param[in] inputFormat The input format -+ * \return All the supported output formats or an empty vector if there are none -+ */ -+std::vector<PixelFormat> SoftwareIsp::formats(PixelFormat inputFormat) -+{ -+ ASSERT(debayer_ != nullptr); -+ -+ return debayer_->formats(inputFormat); -+} -+ -+/** -+ * \brief Get the supported output sizes for the given input format and size -+ * \param[in] inputFormat The input format -+ * \param[in] inputSize The input frame size -+ * \return The valid size range or an empty range if there are none -+ */ -+SizeRange SoftwareIsp::sizes(PixelFormat inputFormat, const Size &inputSize) -+{ -+ ASSERT(debayer_ != nullptr); -+ -+ return debayer_->sizes(inputFormat, inputSize); -+} -+ -+/** -+ * Get the output stride and the frame size in bytes for the given output format and size -+ * \param[in] outputFormat The output format -+ * \param[in] size The output size (width and height in pixels) -+ * \return A tuple of the stride and the frame size in bytes, or a tuple of 0,0 -+ * if there is no valid output config -+ */ -+std::tuple<unsigned int, unsigned int> -+SoftwareIsp::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) -+{ -+ ASSERT(debayer_ != nullptr); -+ -+ return debayer_->strideAndFrameSize(outputFormat, size); -+} -+ -+/** -+ * \brief Configure the SoftwareIsp object according to the passed in parameters -+ * \param[in] inputCfg The input configuration -+ * \param[in] outputCfgs The output configurations -+ * \param[in] sensorControls ControlInfoMap of the controls supported by the sensor -+ * \return 0 on success, a negative errno on failure -+ */ -+int SoftwareIsp::configure(const StreamConfiguration &inputCfg, -+ const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs, -+ const ControlInfoMap &sensorControls) -+{ -+ ASSERT(ipa_ != nullptr && debayer_ != nullptr); -+ -+ int ret = ipa_->configure(sensorControls); -+ if (ret < 0) -+ return ret; -+ -+ return debayer_->configure(inputCfg, outputCfgs); -+} -+ -+/** -+ * \brief Export the buffers from the Software ISP -+ * \param[in] output Output stream index exporting the buffers -+ * \param[in] count Number of buffers to allocate -+ * \param[out] buffers Vector to store the allocated buffers -+ * \return The number of allocated buffers on success or a negative error code -+ * otherwise -+ */ -+int SoftwareIsp::exportBuffers(unsigned int output, unsigned int count, -+ std::vector<std::unique_ptr<FrameBuffer>> *buffers) -+{ -+ ASSERT(debayer_ != nullptr); -+ -+ /* single output for now */ -+ if (output >= 1) -+ return -EINVAL; -+ -+ for (unsigned int i = 0; i < count; i++) { -+ const std::string name = "frame-" + std::to_string(i); -+ const size_t frameSize = debayer_->frameSize(); -+ -+ FrameBuffer::Plane outPlane; -+ outPlane.fd = SharedFD(dmaHeap_.alloc(name.c_str(), frameSize)); -+ if (!outPlane.fd.isValid()) { -+ LOG(SoftwareIsp, Error) -+ << "failed to allocate a dma_buf"; -+ return -ENOMEM; -+ } -+ outPlane.offset = 0; -+ outPlane.length = frameSize; -+ -+ std::vector<FrameBuffer::Plane> planes{ outPlane }; -+ buffers->emplace_back(std::make_unique<FrameBuffer>(std::move(planes))); -+ } -+ -+ return count; -+} -+ -+/** -+ * \brief Queue buffers to Software ISP -+ * \param[in] input The input framebuffer -+ * \param[in] outputs The container holding the output stream indexes and -+ * their respective frame buffer outputs -+ * \return 0 on success, a negative errno on failure -+ */ -+int SoftwareIsp::queueBuffers(FrameBuffer *input, -+ const std::map<unsigned int, FrameBuffer *> &outputs) -+{ -+ unsigned int mask = 0; -+ -+ /* -+ * Validate the outputs as a sanity check: at least one output is -+ * required, all outputs must reference a valid stream and no two -+ * outputs can reference the same stream. -+ */ -+ if (outputs.empty()) -+ return -EINVAL; -+ -+ for (auto [index, buffer] : outputs) { -+ if (!buffer) -+ return -EINVAL; -+ if (index >= 1) /* only single stream atm */ -+ return -EINVAL; -+ if (mask & (1 << index)) -+ return -EINVAL; -+ -+ mask |= 1 << index; -+ } -+ -+ process(input, outputs.at(0)); -+ -+ return 0; -+} -+ -+/** -+ * \brief Starts the Software ISP streaming operation -+ * \return 0 on success, any other value indicates an error -+ */ -+int SoftwareIsp::start() -+{ -+ int ret = ipa_->start(); -+ if (ret) -+ return ret; -+ -+ ispWorkerThread_.start(); -+ return 0; -+} -+ -+/** -+ * \brief Stops the Software ISP streaming operation -+ */ -+void SoftwareIsp::stop() -+{ -+ ispWorkerThread_.exit(); -+ ispWorkerThread_.wait(); -+ -+ ipa_->stop(); -+} -+ -+/** -+ * \brief Passes the input framebuffer to the ISP worker to process -+ * \param[in] input The input framebuffer -+ * \param[out] output The framebuffer to write the processed frame to -+ */ -+void SoftwareIsp::process(FrameBuffer *input, FrameBuffer *output) -+{ -+ debayer_->invokeMethod(&DebayerCpu::process, -+ ConnectionTypeQueued, input, output, debayerParams_); -+} -+ -+void SoftwareIsp::saveIspParams([[maybe_unused]] int dummy) -+{ -+ debayerParams_ = *sharedParams_; -+} -+ -+void SoftwareIsp::setSensorCtrls(const ControlList &sensorControls) -+{ -+ setSensorControls.emit(sensorControls); -+} -+ -+void SoftwareIsp::statsReady(int dummy) -+{ -+ ispStatsReady.emit(dummy); -+} -+ -+void SoftwareIsp::inputReady(FrameBuffer *input) -+{ -+ inputBufferReady.emit(input); -+} -+ -+void SoftwareIsp::outputReady(FrameBuffer *output) -+{ -+ outputBufferReady.emit(output); -+} -+ -+} /* namespace libcamera */ --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0011-libcamera-pipeline-simple-rename-converterBuffers_-a.patch b/users/flokli/ipu6-softisp/libcamera/0011-libcamera-pipeline-simple-rename-converterBuffers_-a.patch deleted file mode 100644 index 5c2237a8eb01..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0011-libcamera-pipeline-simple-rename-converterBuffers_-a.patch +++ /dev/null @@ -1,240 +0,0 @@ -From 050440eed6ab90686df217f5ff7dea0b241e3898 Mon Sep 17 00:00:00 2001 -From: Andrey Konovalov <andrey.konovalov@linaro.org> -Date: Mon, 11 Mar 2024 15:15:15 +0100 -Subject: [PATCH 11/21] libcamera: pipeline: simple: rename converterBuffers_ - and related vars - -The converterBuffers_ and the converterQueue_ are not that specific -to the Converter, and could be used by another entity doing the format -conversion. - -Rename converterBuffers_, converterQueue_, and useConverter_ to -conversionBuffers_, conversionQueue_ and useConversion_ to -disassociate them from the Converter. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - src/libcamera/pipeline/simple/simple.cpp | 63 ++++++++++++------------ - 1 file changed, 32 insertions(+), 31 deletions(-) - -diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp -index a84f6760..78854ef8 100644 ---- a/src/libcamera/pipeline/simple/simple.cpp -+++ b/src/libcamera/pipeline/simple/simple.cpp -@@ -269,17 +269,18 @@ public: - std::vector<Configuration> configs_; - std::map<PixelFormat, std::vector<const Configuration *>> formats_; - -+ std::vector<std::unique_ptr<FrameBuffer>> conversionBuffers_; -+ std::queue<std::map<unsigned int, FrameBuffer *>> conversionQueue_; -+ bool useConversion_; -+ - std::unique_ptr<Converter> converter_; -- std::vector<std::unique_ptr<FrameBuffer>> converterBuffers_; -- bool useConverter_; -- std::queue<std::map<unsigned int, FrameBuffer *>> converterQueue_; - - private: - void tryPipeline(unsigned int code, const Size &size); - static std::vector<const MediaPad *> routedSourcePads(MediaPad *sink); - -- void converterInputDone(FrameBuffer *buffer); -- void converterOutputDone(FrameBuffer *buffer); -+ void conversionInputDone(FrameBuffer *buffer); -+ void conversionOutputDone(FrameBuffer *buffer); - }; - - class SimpleCameraConfiguration : public CameraConfiguration -@@ -503,8 +504,8 @@ int SimpleCameraData::init() - << "Failed to create converter, disabling format conversion"; - converter_.reset(); - } else { -- converter_->inputBufferReady.connect(this, &SimpleCameraData::converterInputDone); -- converter_->outputBufferReady.connect(this, &SimpleCameraData::converterOutputDone); -+ converter_->inputBufferReady.connect(this, &SimpleCameraData::conversionInputDone); -+ converter_->outputBufferReady.connect(this, &SimpleCameraData::conversionOutputDone); - } - } - -@@ -740,7 +741,7 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer) - * point converting an erroneous buffer. - */ - if (buffer->metadata().status != FrameMetadata::FrameSuccess) { -- if (!useConverter_) { -+ if (!useConversion_) { - /* No conversion, just complete the request. */ - Request *request = buffer->request(); - pipe->completeBuffer(request, buffer); -@@ -756,16 +757,16 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer) - if (buffer->metadata().status != FrameMetadata::FrameCancelled) - video_->queueBuffer(buffer); - -- if (converterQueue_.empty()) -+ if (conversionQueue_.empty()) - return; - - Request *request = nullptr; -- for (auto &item : converterQueue_.front()) { -+ for (auto &item : conversionQueue_.front()) { - FrameBuffer *outputBuffer = item.second; - request = outputBuffer->request(); - pipe->completeBuffer(request, outputBuffer); - } -- converterQueue_.pop(); -+ conversionQueue_.pop(); - - if (request) - pipe->completeRequest(request); -@@ -782,9 +783,9 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer) - */ - Request *request = buffer->request(); - -- if (useConverter_ && !converterQueue_.empty()) { -+ if (useConversion_ && !conversionQueue_.empty()) { - const std::map<unsigned int, FrameBuffer *> &outputs = -- converterQueue_.front(); -+ conversionQueue_.front(); - if (!outputs.empty()) { - FrameBuffer *outputBuffer = outputs.begin()->second; - if (outputBuffer) -@@ -801,14 +802,14 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer) - * conversion is needed. If there's no queued request, just requeue the - * captured buffer for capture. - */ -- if (useConverter_) { -- if (converterQueue_.empty()) { -+ if (useConversion_) { -+ if (conversionQueue_.empty()) { - video_->queueBuffer(buffer); - return; - } - -- converter_->queueBuffers(buffer, converterQueue_.front()); -- converterQueue_.pop(); -+ converter_->queueBuffers(buffer, conversionQueue_.front()); -+ conversionQueue_.pop(); - return; - } - -@@ -817,13 +818,13 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer) - pipe->completeRequest(request); - } - --void SimpleCameraData::converterInputDone(FrameBuffer *buffer) -+void SimpleCameraData::conversionInputDone(FrameBuffer *buffer) - { - /* Queue the input buffer back for capture. */ - video_->queueBuffer(buffer); - } - --void SimpleCameraData::converterOutputDone(FrameBuffer *buffer) -+void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer) - { - SimplePipelineHandler *pipe = SimpleCameraData::pipe(); - -@@ -1189,14 +1190,14 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c) - - /* Configure the converter if needed. */ - std::vector<std::reference_wrapper<StreamConfiguration>> outputCfgs; -- data->useConverter_ = config->needConversion(); -+ data->useConversion_ = config->needConversion(); - - for (unsigned int i = 0; i < config->size(); ++i) { - StreamConfiguration &cfg = config->at(i); - - cfg.setStream(&data->streams_[i]); - -- if (data->useConverter_) -+ if (data->useConversion_) - outputCfgs.push_back(cfg); - } - -@@ -1222,7 +1223,7 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream, - * Export buffers on the converter or capture video node, depending on - * whether the converter is used or not. - */ -- if (data->useConverter_) -+ if (data->useConversion_) - return data->converter_->exportBuffers(data->streamIndex(stream), - count, buffers); - else -@@ -1243,13 +1244,13 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL - return -EBUSY; - } - -- if (data->useConverter_) { -+ if (data->useConversion_) { - /* - * When using the converter allocate a fixed number of internal - * buffers. - */ - ret = video->allocateBuffers(kNumInternalBuffers, -- &data->converterBuffers_); -+ &data->conversionBuffers_); - } else { - /* Otherwise, prepare for using buffers from the only stream. */ - Stream *stream = &data->streams_[0]; -@@ -1268,7 +1269,7 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL - return ret; - } - -- if (data->useConverter_) { -+ if (data->useConversion_) { - ret = data->converter_->start(); - if (ret < 0) { - stop(camera); -@@ -1276,7 +1277,7 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL - } - - /* Queue all internal buffers for capture. */ -- for (std::unique_ptr<FrameBuffer> &buffer : data->converterBuffers_) -+ for (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_) - video->queueBuffer(buffer.get()); - } - -@@ -1288,7 +1289,7 @@ void SimplePipelineHandler::stopDevice(Camera *camera) - SimpleCameraData *data = cameraData(camera); - V4L2VideoDevice *video = data->video_; - -- if (data->useConverter_) -+ if (data->useConversion_) - data->converter_->stop(); - - video->streamOff(); -@@ -1296,7 +1297,7 @@ void SimplePipelineHandler::stopDevice(Camera *camera) - - video->bufferReady.disconnect(data, &SimpleCameraData::bufferReady); - -- data->converterBuffers_.clear(); -+ data->conversionBuffers_.clear(); - - releasePipeline(data); - } -@@ -1314,7 +1315,7 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request) - * queue, it will be handed to the converter in the capture - * completion handler. - */ -- if (data->useConverter_) { -+ if (data->useConversion_) { - buffers.emplace(data->streamIndex(stream), buffer); - } else { - ret = data->video_->queueBuffer(buffer); -@@ -1323,8 +1324,8 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request) - } - } - -- if (data->useConverter_) -- data->converterQueue_.push(std::move(buffers)); -+ if (data->useConversion_) -+ data->conversionQueue_.push(std::move(buffers)); - - return 0; - } --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0012-libcamera-pipeline-simple-enable-use-of-Soft-ISP-and.patch b/users/flokli/ipu6-softisp/libcamera/0012-libcamera-pipeline-simple-enable-use-of-Soft-ISP-and.patch deleted file mode 100644 index 378a43604f9a..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0012-libcamera-pipeline-simple-enable-use-of-Soft-ISP-and.patch +++ /dev/null @@ -1,302 +0,0 @@ -From d64b0fca22ef25b8a14d7fc97dfab64eb1c4f21a Mon Sep 17 00:00:00 2001 -From: Andrey Konovalov <andrey.konovalov@linaro.org> -Date: Mon, 11 Mar 2024 15:15:16 +0100 -Subject: [PATCH 12/21] libcamera: pipeline: simple: enable use of Soft ISP and - Soft IPA - -To enable the Simple Soft ISP and Soft IPA for simple pipeline handler -configure the build with: - -Dpipelines=simple -Dipas=simple - -Also using the Soft ISP for the particular hardware platform must -be enabled in the supportedDevices[] table. - -If the pipeline uses Converter, Soft ISP and Soft IPA aren't -available. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - src/libcamera/pipeline/simple/simple.cpp | 137 ++++++++++++++++++----- - 1 file changed, 109 insertions(+), 28 deletions(-) - -diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp -index 78854ef8..c3ebb7b7 100644 ---- a/src/libcamera/pipeline/simple/simple.cpp -+++ b/src/libcamera/pipeline/simple/simple.cpp -@@ -34,6 +34,7 @@ - #include "libcamera/internal/device_enumerator.h" - #include "libcamera/internal/media_device.h" - #include "libcamera/internal/pipeline_handler.h" -+#include "libcamera/internal/software_isp/software_isp.h" - #include "libcamera/internal/v4l2_subdevice.h" - #include "libcamera/internal/v4l2_videodevice.h" - -@@ -185,17 +186,22 @@ struct SimplePipelineInfo { - * and the number of streams it supports. - */ - std::vector<std::pair<const char *, unsigned int>> converters; -+ /* -+ * Using Software ISP is to be enabled per driver. -+ * The Software ISP can't be used together with the converters. -+ */ -+ bool swIspEnabled; - }; - - namespace { - - static const SimplePipelineInfo supportedDevices[] = { -- { "dcmipp", {} }, -- { "imx7-csi", { { "pxp", 1 } } }, -- { "j721e-csi2rx", {} }, -- { "mxc-isi", {} }, -- { "qcom-camss", {} }, -- { "sun6i-csi", {} }, -+ { "dcmipp", {}, false }, -+ { "imx7-csi", { { "pxp", 1 } }, false }, -+ { "j721e-csi2rx", {}, false }, -+ { "mxc-isi", {}, false }, -+ { "qcom-camss", {}, true }, -+ { "sun6i-csi", {}, false }, - }; - - } /* namespace */ -@@ -274,6 +280,7 @@ public: - bool useConversion_; - - std::unique_ptr<Converter> converter_; -+ std::unique_ptr<SoftwareIsp> swIsp_; - - private: - void tryPipeline(unsigned int code, const Size &size); -@@ -281,6 +288,9 @@ private: - - void conversionInputDone(FrameBuffer *buffer); - void conversionOutputDone(FrameBuffer *buffer); -+ -+ void ispStatsReady(int dummy); -+ void setSensorControls(const ControlList &sensorControls); - }; - - class SimpleCameraConfiguration : public CameraConfiguration -@@ -332,6 +342,7 @@ public: - V4L2VideoDevice *video(const MediaEntity *entity); - V4L2Subdevice *subdev(const MediaEntity *entity); - MediaDevice *converter() { return converter_; } -+ bool swIspEnabled() { return swIspEnabled_; } - - protected: - int queueRequestDevice(Camera *camera, Request *request) override; -@@ -360,6 +371,7 @@ private: - std::map<const MediaEntity *, EntityData> entities_; - - MediaDevice *converter_; -+ bool swIspEnabled_; - }; - - /* ----------------------------------------------------------------------------- -@@ -509,6 +521,29 @@ int SimpleCameraData::init() - } - } - -+ /* -+ * Instantiate Soft ISP if this is enabled for the given driver and no converter is used. -+ */ -+ if (!converter_ && pipe->swIspEnabled()) { -+ swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_->controls()); -+ if (!swIsp_->isValid()) { -+ LOG(SimplePipeline, Warning) -+ << "Failed to create software ISP, disabling software debayering"; -+ swIsp_.reset(); -+ } else { -+ /* -+ * \todo explain why SimpleCameraData::conversionInputDone() can't be directly -+ * connected to inputBufferReady signal. -+ */ -+ swIsp_->inputBufferReady.connect(pipe, [this](FrameBuffer *buffer) { -+ this->conversionInputDone(buffer); -+ }); -+ swIsp_->outputBufferReady.connect(this, &SimpleCameraData::conversionOutputDone); -+ swIsp_->ispStatsReady.connect(this, &SimpleCameraData::ispStatsReady); -+ swIsp_->setSensorControls.connect(this, &SimpleCameraData::setSensorControls); -+ } -+ } -+ - video_ = pipe->video(entities_.back().entity); - ASSERT(video_); - -@@ -599,12 +634,21 @@ void SimpleCameraData::tryPipeline(unsigned int code, const Size &size) - config.captureFormat = pixelFormat; - config.captureSize = format.size; - -- if (!converter_) { -+ -+ if (converter_) { -+ config.outputFormats = converter_->formats(pixelFormat); -+ config.outputSizes = converter_->sizes(format.size); -+ } else if (swIsp_) { -+ config.outputFormats = swIsp_->formats(pixelFormat); -+ config.outputSizes = swIsp_->sizes(pixelFormat, format.size); -+ if (config.outputFormats.empty()) { -+ /* Do not use swIsp for unsupported pixelFormat's: */ -+ config.outputFormats = { pixelFormat }; -+ config.outputSizes = config.captureSize; -+ } -+ } else { - config.outputFormats = { pixelFormat }; - config.outputSizes = config.captureSize; -- } else { -- config.outputFormats = converter_->formats(pixelFormat); -- config.outputSizes = converter_->sizes(format.size); - } - - configs_.push_back(config); -@@ -750,9 +794,9 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer) - } - - /* -- * The converter is in use. Requeue the internal buffer for -- * capture (unless the stream is being stopped), and complete -- * the request with all the user-facing buffers. -+ * The converter or Software ISP is in use. Requeue the internal -+ * buffer for capture (unless the stream is being stopped), and -+ * complete the request with all the user-facing buffers. - */ - if (buffer->metadata().status != FrameMetadata::FrameCancelled) - video_->queueBuffer(buffer); -@@ -798,9 +842,9 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer) - buffer->metadata().timestamp); - - /* -- * Queue the captured and the request buffer to the converter if format -- * conversion is needed. If there's no queued request, just requeue the -- * captured buffer for capture. -+ * Queue the captured and the request buffer to the converter or Software -+ * ISP if format conversion is needed. If there's no queued request, just -+ * requeue the captured buffer for capture. - */ - if (useConversion_) { - if (conversionQueue_.empty()) { -@@ -808,7 +852,11 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer) - return; - } - -- converter_->queueBuffers(buffer, conversionQueue_.front()); -+ if (converter_) -+ converter_->queueBuffers(buffer, conversionQueue_.front()); -+ else -+ swIsp_->queueBuffers(buffer, conversionQueue_.front()); -+ - conversionQueue_.pop(); - return; - } -@@ -834,6 +882,18 @@ void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer) - pipe->completeRequest(request); - } - -+void SimpleCameraData::ispStatsReady([[maybe_unused]] int dummy) -+{ -+ swIsp_->processStats(sensor_->getControls({ V4L2_CID_ANALOGUE_GAIN, -+ V4L2_CID_EXPOSURE })); -+} -+ -+void SimpleCameraData::setSensorControls(const ControlList &sensorControls) -+{ -+ ControlList ctrls(sensorControls); -+ sensor_->setControls(&ctrls); -+} -+ - /* Retrieve all source pads connected to a sink pad through active routes. */ - std::vector<const MediaPad *> SimpleCameraData::routedSourcePads(MediaPad *sink) - { -@@ -1046,8 +1106,10 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate() - /* Set the stride, frameSize and bufferCount. */ - if (needConversion_) { - std::tie(cfg.stride, cfg.frameSize) = -- data_->converter_->strideAndFrameSize(cfg.pixelFormat, -- cfg.size); -+ (data_->converter_) ? data_->converter_->strideAndFrameSize(cfg.pixelFormat, -+ cfg.size) -+ : data_->swIsp_->strideAndFrameSize(cfg.pixelFormat, -+ cfg.size); - if (cfg.stride == 0) - return Invalid; - } else { -@@ -1210,7 +1272,9 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c) - inputCfg.stride = captureFormat.planes[0].bpl; - inputCfg.bufferCount = kNumInternalBuffers; - -- return data->converter_->configure(inputCfg, outputCfgs); -+ return (data->converter_) ? data->converter_->configure(inputCfg, outputCfgs) -+ : data->swIsp_->configure(inputCfg, outputCfgs, -+ data->sensor_->controls()); - } - - int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream, -@@ -1224,8 +1288,10 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream, - * whether the converter is used or not. - */ - if (data->useConversion_) -- return data->converter_->exportBuffers(data->streamIndex(stream), -- count, buffers); -+ return (data->converter_) ? data->converter_->exportBuffers(data->streamIndex(stream), -+ count, buffers) -+ : data->swIsp_->exportBuffers(data->streamIndex(stream), -+ count, buffers); - else - return data->video_->exportBuffers(count, buffers); - } -@@ -1270,10 +1336,18 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL - } - - if (data->useConversion_) { -- ret = data->converter_->start(); -- if (ret < 0) { -- stop(camera); -- return ret; -+ if (data->converter_) { -+ ret = data->converter_->start(); -+ if (ret < 0) { -+ stop(camera); -+ return ret; -+ } -+ } else if (data->swIsp_) { -+ ret = data->swIsp_->start(); -+ if (ret < 0) { -+ stop(camera); -+ return ret; -+ } - } - - /* Queue all internal buffers for capture. */ -@@ -1289,8 +1363,13 @@ void SimplePipelineHandler::stopDevice(Camera *camera) - SimpleCameraData *data = cameraData(camera); - V4L2VideoDevice *video = data->video_; - -- if (data->useConversion_) -- data->converter_->stop(); -+ if (data->useConversion_) { -+ if (data->converter_) -+ data->converter_->stop(); -+ else if (data->swIsp_) { -+ data->swIsp_->stop(); -+ } -+ } - - video->streamOff(); - video->releaseBuffers(); -@@ -1452,6 +1531,8 @@ bool SimplePipelineHandler::match(DeviceEnumerator *enumerator) - } - } - -+ swIspEnabled_ = info->swIspEnabled; -+ - /* Locate the sensors. */ - std::vector<MediaEntity *> sensors = locateSensors(); - if (sensors.empty()) { --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0013-libcamera-swstats_cpu-Add-support-for-8-10-and-12-bp.patch b/users/flokli/ipu6-softisp/libcamera/0013-libcamera-swstats_cpu-Add-support-for-8-10-and-12-bp.patch deleted file mode 100644 index 1a57d690ff91..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0013-libcamera-swstats_cpu-Add-support-for-8-10-and-12-bp.patch +++ /dev/null @@ -1,203 +0,0 @@ -From aabc53453d542495d9da25411f57308c01f2bc28 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Mon, 11 Mar 2024 15:15:17 +0100 -Subject: [PATCH 13/21] libcamera: swstats_cpu: Add support for 8, 10 and 12 - bpp unpacked bayer input - -Add support for 8, 10 and 12 bpp unpacked bayer input for all 4 standard -bayer orders. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> -Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - src/libcamera/software_isp/swstats_cpu.cpp | 128 +++++++++++++++++++++ - src/libcamera/software_isp/swstats_cpu.h | 9 ++ - 2 files changed, 137 insertions(+) - -diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp -index 448d0e4c..be310f56 100644 ---- a/src/libcamera/software_isp/swstats_cpu.cpp -+++ b/src/libcamera/software_isp/swstats_cpu.cpp -@@ -71,6 +71,83 @@ static const unsigned int kBlueYMul = 29; /* 0.114 * 256 */ - stats_.sumG_ += sumG; \ - stats_.sumB_ += sumB; - -+void SwStatsCpu::statsBGGR8Line0(const uint8_t *src[]) -+{ -+ const uint8_t *src0 = src[1] + window_.x; -+ const uint8_t *src1 = src[2] + window_.x; -+ -+ SWSTATS_START_LINE_STATS(uint8_t) -+ -+ if (swapLines_) -+ std::swap(src0, src1); -+ -+ /* x += 4 sample every other 2x2 block */ -+ for (int x = 0; x < (int)window_.width; x += 4) { -+ b = src0[x]; -+ g = src0[x + 1]; -+ g2 = src1[x]; -+ r = src1[x + 1]; -+ -+ g = (g + g2) / 2; -+ -+ SWSTATS_ACCUMULATE_LINE_STATS(1) -+ } -+ -+ SWSTATS_FINISH_LINE_STATS() -+} -+ -+void SwStatsCpu::statsBGGR10Line0(const uint8_t *src[]) -+{ -+ const uint16_t *src0 = (const uint16_t *)src[1] + window_.x; -+ const uint16_t *src1 = (const uint16_t *)src[2] + window_.x; -+ -+ SWSTATS_START_LINE_STATS(uint16_t) -+ -+ if (swapLines_) -+ std::swap(src0, src1); -+ -+ /* x += 4 sample every other 2x2 block */ -+ for (int x = 0; x < (int)window_.width; x += 4) { -+ b = src0[x]; -+ g = src0[x + 1]; -+ g2 = src1[x]; -+ r = src1[x + 1]; -+ -+ g = (g + g2) / 2; -+ -+ /* divide Y by 4 for 10 -> 8 bpp value */ -+ SWSTATS_ACCUMULATE_LINE_STATS(4) -+ } -+ -+ SWSTATS_FINISH_LINE_STATS() -+} -+ -+void SwStatsCpu::statsBGGR12Line0(const uint8_t *src[]) -+{ -+ const uint16_t *src0 = (const uint16_t *)src[1] + window_.x; -+ const uint16_t *src1 = (const uint16_t *)src[2] + window_.x; -+ -+ SWSTATS_START_LINE_STATS(uint16_t) -+ -+ if (swapLines_) -+ std::swap(src0, src1); -+ -+ /* x += 4 sample every other 2x2 block */ -+ for (int x = 0; x < (int)window_.width; x += 4) { -+ b = src0[x]; -+ g = src0[x + 1]; -+ g2 = src1[x]; -+ r = src1[x + 1]; -+ -+ g = (g + g2) / 2; -+ -+ /* divide Y by 16 for 12 -> 8 bpp value */ -+ SWSTATS_ACCUMULATE_LINE_STATS(16) -+ } -+ -+ SWSTATS_FINISH_LINE_STATS() -+} -+ - void SwStatsCpu::statsBGGR10PLine0(const uint8_t *src[]) - { - const uint8_t *src0 = src[1] + window_.x * 5 / 4; -@@ -147,6 +224,42 @@ void SwStatsCpu::finishFrame(void) - statsReady.emit(0); - } - -+/** -+ * \brief Setup SwStatsCpu object for standard Bayer orders -+ * \param[in] order The Bayer order -+ * -+ * Check if order is a standard Bayer order and setup xShift_ and swapLines_ -+ * so that a single BGGR stats function can be used for all 4 standard orders. -+ */ -+int SwStatsCpu::setupStandardBayerOrder(BayerFormat::Order order) -+{ -+ switch (order) { -+ case BayerFormat::BGGR: -+ xShift_ = 0; -+ swapLines_ = false; -+ break; -+ case BayerFormat::GBRG: -+ xShift_ = 1; /* BGGR -> GBRG */ -+ swapLines_ = false; -+ break; -+ case BayerFormat::GRBG: -+ xShift_ = 0; -+ swapLines_ = true; /* BGGR -> GRBG */ -+ break; -+ case BayerFormat::RGGB: -+ xShift_ = 1; /* BGGR -> GBRG */ -+ swapLines_ = true; /* GBRG -> RGGB */ -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ patternSize_.height = 2; -+ patternSize_.width = 2; -+ ySkipMask_ = 0x02; /* Skip every 3th and 4th line */ -+ return 0; -+} -+ - /** - * \brief Configure the statistics object for the passed in input format. - * \param[in] inputCfg The input format -@@ -158,6 +271,21 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg) - BayerFormat bayerFormat = - BayerFormat::fromPixelFormat(inputCfg.pixelFormat); - -+ if (bayerFormat.packing == BayerFormat::Packing::None && -+ setupStandardBayerOrder(bayerFormat.order) == 0) { -+ switch (bayerFormat.bitDepth) { -+ case 8: -+ stats0_ = &SwStatsCpu::statsBGGR8Line0; -+ return 0; -+ case 10: -+ stats0_ = &SwStatsCpu::statsBGGR10Line0; -+ return 0; -+ case 12: -+ stats0_ = &SwStatsCpu::statsBGGR12Line0; -+ return 0; -+ } -+ } -+ - if (bayerFormat.bitDepth == 10 && - bayerFormat.packing == BayerFormat::Packing::CSI2) { - patternSize_.height = 2; -diff --git a/src/libcamera/software_isp/swstats_cpu.h b/src/libcamera/software_isp/swstats_cpu.h -index 0ac9ae71..bbbcf69b 100644 ---- a/src/libcamera/software_isp/swstats_cpu.h -+++ b/src/libcamera/software_isp/swstats_cpu.h -@@ -17,6 +17,7 @@ - - #include <libcamera/geometry.h> - -+#include "libcamera/internal/bayer_format.h" - #include "libcamera/internal/shared_mem_object.h" - #include "libcamera/internal/software_isp/swisp_stats.h" - -@@ -120,6 +121,14 @@ private: - */ - using statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[]); - -+ int setupStandardBayerOrder(BayerFormat::Order order); -+ /* Bayer 8 bpp unpacked */ -+ void statsBGGR8Line0(const uint8_t *src[]); -+ /* Bayer 10 bpp unpacked */ -+ void statsBGGR10Line0(const uint8_t *src[]); -+ /* Bayer 12 bpp unpacked */ -+ void statsBGGR12Line0(const uint8_t *src[]); -+ /* Bayer 10 bpp packed */ - void statsBGGR10PLine0(const uint8_t *src[]); - void statsGBRG10PLine0(const uint8_t *src[]); - --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0014-libcamera-debayer_cpu-Add-support-for-8-10-and-12-bp.patch b/users/flokli/ipu6-softisp/libcamera/0014-libcamera-debayer_cpu-Add-support-for-8-10-and-12-bp.patch deleted file mode 100644 index c7edf498280e..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0014-libcamera-debayer_cpu-Add-support-for-8-10-and-12-bp.patch +++ /dev/null @@ -1,234 +0,0 @@ -From 5f3647bd4f12dd62256a425c49fd18a0f5990930 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Mon, 11 Mar 2024 15:15:18 +0100 -Subject: [PATCH 14/21] libcamera: debayer_cpu: Add support for 8, 10 and 12 - bpp unpacked bayer input - -Add support for 8, 10 and 12 bpp unpacked bayer input for all 4 standard -bayer orders. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> -Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - src/libcamera/software_isp/debayer_cpu.cpp | 128 +++++++++++++++++++++ - src/libcamera/software_isp/debayer_cpu.h | 13 +++ - 2 files changed, 141 insertions(+) - -diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp -index f932362c..eb1c2718 100644 ---- a/src/libcamera/software_isp/debayer_cpu.cpp -+++ b/src/libcamera/software_isp/debayer_cpu.cpp -@@ -56,6 +56,11 @@ DebayerCpu::~DebayerCpu() - free(lineBuffers_[i]); - } - -+#define DECLARE_SRC_POINTERS(pixel_t) \ -+ const pixel_t *prev = (const pixel_t *)src[0] + xShift_; \ -+ const pixel_t *curr = (const pixel_t *)src[1] + xShift_; \ -+ const pixel_t *next = (const pixel_t *)src[2] + xShift_; -+ - // RGR - // GBG - // RGR -@@ -92,6 +97,70 @@ DebayerCpu::~DebayerCpu() - *dst++ = red_[curr[x] / (div)]; \ - x++; - -+void DebayerCpu::debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ DECLARE_SRC_POINTERS(uint8_t) -+ -+ for (int x = 0; x < (int)window_.width;) { -+ BGGR_BGR888(1, 1, 1) -+ GBRG_BGR888(1, 1, 1) -+ } -+} -+ -+void DebayerCpu::debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ DECLARE_SRC_POINTERS(uint8_t) -+ -+ for (int x = 0; x < (int)window_.width;) { -+ GRBG_BGR888(1, 1, 1) -+ RGGB_BGR888(1, 1, 1) -+ } -+} -+ -+void DebayerCpu::debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ DECLARE_SRC_POINTERS(uint16_t) -+ -+ for (int x = 0; x < (int)window_.width;) { -+ /* divide values by 4 for 10 -> 8 bpp value */ -+ BGGR_BGR888(1, 1, 4) -+ GBRG_BGR888(1, 1, 4) -+ } -+} -+ -+void DebayerCpu::debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ DECLARE_SRC_POINTERS(uint16_t) -+ -+ for (int x = 0; x < (int)window_.width;) { -+ /* divide values by 4 for 10 -> 8 bpp value */ -+ GRBG_BGR888(1, 1, 4) -+ RGGB_BGR888(1, 1, 4) -+ } -+} -+ -+void DebayerCpu::debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ DECLARE_SRC_POINTERS(uint16_t) -+ -+ for (int x = 0; x < (int)window_.width;) { -+ /* divide values by 16 for 12 -> 8 bpp value */ -+ BGGR_BGR888(1, 1, 16) -+ GBRG_BGR888(1, 1, 16) -+ } -+} -+ -+void DebayerCpu::debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]) -+{ -+ DECLARE_SRC_POINTERS(uint16_t) -+ -+ for (int x = 0; x < (int)window_.width;) { -+ /* divide values by 16 for 12 -> 8 bpp value */ -+ GRBG_BGR888(1, 1, 16) -+ RGGB_BGR888(1, 1, 16) -+ } -+} -+ - void DebayerCpu::debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]) - { - const int width_in_bytes = window_.width * 5 / 4; -@@ -193,6 +262,16 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf - BayerFormat bayerFormat = - BayerFormat::fromPixelFormat(inputFormat); - -+ if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) && -+ bayerFormat.packing == BayerFormat::Packing::None && -+ isStandardBayerOrder(bayerFormat.order)) { -+ config.bpp = (bayerFormat.bitDepth + 7) & ~7; -+ config.patternSize.width = 2; -+ config.patternSize.height = 2; -+ config.outputFormats = std::vector<PixelFormat>({ formats::RGB888 }); -+ return 0; -+ } -+ - if (bayerFormat.bitDepth == 10 && - bayerFormat.packing == BayerFormat::Packing::CSI2 && - isStandardBayerOrder(bayerFormat.order)) { -@@ -220,12 +299,61 @@ int DebayerCpu::getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &c - return -EINVAL; - } - -+/* -+ * Check for standard Bayer orders and set xShift_ and swap debayer0/1, so that -+ * a single pair of BGGR debayer functions can be used for all 4 standard orders. -+ */ -+int DebayerCpu::setupStandardBayerOrder(BayerFormat::Order order) -+{ -+ switch (order) { -+ case BayerFormat::BGGR: -+ break; -+ case BayerFormat::GBRG: -+ xShift_ = 1; /* BGGR -> GBRG */ -+ break; -+ case BayerFormat::GRBG: -+ std::swap(debayer0_, debayer1_); /* BGGR -> GRBG */ -+ break; -+ case BayerFormat::RGGB: -+ xShift_ = 1; /* BGGR -> GBRG */ -+ std::swap(debayer0_, debayer1_); /* GBRG -> RGGB */ -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ - /* TODO: this ignores outputFormat since there is only 1 supported outputFormat for now */ - int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, [[maybe_unused]] PixelFormat outputFormat) - { - BayerFormat bayerFormat = - BayerFormat::fromPixelFormat(inputFormat); - -+ xShift_ = 0; -+ -+ if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) && -+ bayerFormat.packing == BayerFormat::Packing::None && -+ isStandardBayerOrder(bayerFormat.order)) { -+ switch (bayerFormat.bitDepth) { -+ case 8: -+ debayer0_ = &DebayerCpu::debayer8_BGBG_BGR888; -+ debayer1_ = &DebayerCpu::debayer8_GRGR_BGR888; -+ break; -+ case 10: -+ debayer0_ = &DebayerCpu::debayer10_BGBG_BGR888; -+ debayer1_ = &DebayerCpu::debayer10_GRGR_BGR888; -+ break; -+ case 12: -+ debayer0_ = &DebayerCpu::debayer12_BGBG_BGR888; -+ debayer1_ = &DebayerCpu::debayer12_GRGR_BGR888; -+ break; -+ } -+ setupStandardBayerOrder(bayerFormat.order); -+ return 0; -+ } -+ - if (bayerFormat.bitDepth == 10 && - bayerFormat.packing == BayerFormat::Packing::CSI2) { - switch (bayerFormat.order) { -diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h -index 8a51ed85..fd1fa180 100644 ---- a/src/libcamera/software_isp/debayer_cpu.h -+++ b/src/libcamera/software_isp/debayer_cpu.h -@@ -17,6 +17,8 @@ - - #include <libcamera/base/object.h> - -+#include "libcamera/internal/bayer_format.h" -+ - #include "debayer.h" - #include "swstats_cpu.h" - -@@ -82,6 +84,15 @@ private: - */ - using debayerFn = void (DebayerCpu::*)(uint8_t *dst, const uint8_t *src[]); - -+ /* 8-bit raw bayer format */ -+ void debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]); -+ void debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]); -+ /* unpacked 10-bit raw bayer format */ -+ void debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]); -+ void debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]); -+ /* unpacked 12-bit raw bayer format */ -+ void debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]); -+ void debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]); - /* CSI-2 packed 10-bit raw bayer format (all the 4 orders) */ - void debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]); - void debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]); -@@ -103,6 +114,7 @@ private: - - int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config); - int getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config); -+ int setupStandardBayerOrder(BayerFormat::Order order); - int setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputFormat); - void setupInputMemcpy(const uint8_t *linePointers[]); - void shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src); -@@ -131,6 +143,7 @@ private: - unsigned int lineBufferLength_; - unsigned int lineBufferPadding_; - unsigned int lineBufferIndex_; -+ unsigned int xShift_; /* Offset of 0/1 applied to window_.x */ - bool enableInputMemcpy_; - float gamma_correction_; - unsigned int measuredFrames_; --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0015-libcamera-debayer_cpu-Add-BGR888-output-support.patch b/users/flokli/ipu6-softisp/libcamera/0015-libcamera-debayer_cpu-Add-BGR888-output-support.patch deleted file mode 100644 index 0abca2ea82d9..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0015-libcamera-debayer_cpu-Add-BGR888-output-support.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 186db51d54bcbd4d5096bea1e4396966c2dad001 Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Mon, 11 Mar 2024 15:15:19 +0100 -Subject: [PATCH 15/21] libcamera: debayer_cpu: Add BGR888 output support - -BGR888 is RGB888 with the red and blue pixels swapped, adjust -the debayering to swap the red and blue pixels in the bayer pattern -to add support for writing formats::BGR888. - -Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s -Tested-by: Pavel Machek <pavel@ucw.cz> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> ---- - src/libcamera/software_isp/debayer_cpu.cpp | 42 +++++++++++++++++++--- - src/libcamera/software_isp/debayer_cpu.h | 1 + - 2 files changed, 38 insertions(+), 5 deletions(-) - -diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp -index eb1c2718..a1692693 100644 ---- a/src/libcamera/software_isp/debayer_cpu.cpp -+++ b/src/libcamera/software_isp/debayer_cpu.cpp -@@ -268,7 +268,7 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf - config.bpp = (bayerFormat.bitDepth + 7) & ~7; - config.patternSize.width = 2; - config.patternSize.height = 2; -- config.outputFormats = std::vector<PixelFormat>({ formats::RGB888 }); -+ config.outputFormats = std::vector<PixelFormat>({ formats::RGB888, formats::BGR888 }); - return 0; - } - -@@ -278,7 +278,7 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf - config.bpp = 10; - config.patternSize.width = 4; /* 5 bytes per *4* pixels */ - config.patternSize.height = 2; -- config.outputFormats = std::vector<PixelFormat>({ formats::RGB888 }); -+ config.outputFormats = std::vector<PixelFormat>({ formats::RGB888, formats::BGR888 }); - return 0; - } - -@@ -289,7 +289,7 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf - - int DebayerCpu::getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config) - { -- if (outputFormat == formats::RGB888) { -+ if (outputFormat == formats::RGB888 || outputFormat == formats::BGR888) { - config.bpp = 24; - return 0; - } -@@ -325,13 +325,41 @@ int DebayerCpu::setupStandardBayerOrder(BayerFormat::Order order) - return 0; - } - --/* TODO: this ignores outputFormat since there is only 1 supported outputFormat for now */ --int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, [[maybe_unused]] PixelFormat outputFormat) -+int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputFormat) - { - BayerFormat bayerFormat = - BayerFormat::fromPixelFormat(inputFormat); - - xShift_ = 0; -+ swapRedBlueGains_ = false; -+ -+ switch (outputFormat) { -+ case formats::RGB888: -+ break; -+ case formats::BGR888: -+ /* Swap R and B in bayer order to generate BGR888 instead of RGB888 */ -+ swapRedBlueGains_ = true; -+ -+ switch (bayerFormat.order) { -+ case BayerFormat::BGGR: -+ bayerFormat.order = BayerFormat::RGGB; -+ break; -+ case BayerFormat::GBRG: -+ bayerFormat.order = BayerFormat::GRBG; -+ break; -+ case BayerFormat::GRBG: -+ bayerFormat.order = BayerFormat::GBRG; -+ break; -+ case BayerFormat::RGGB: -+ bayerFormat.order = BayerFormat::BGGR; -+ break; -+ default: -+ goto invalid_fmt; -+ } -+ break; -+ default: -+ goto invalid_fmt; -+ } - - if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) && - bayerFormat.packing == BayerFormat::Packing::None && -@@ -378,6 +406,7 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, [[maybe_unused]] Pi - } - } - -+invalid_fmt: - LOG(Debayer, Error) << "Unsupported input output format combination"; - return -EINVAL; - } -@@ -661,6 +690,9 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams - gamma_correction_ = params.gamma; - } - -+ if (swapRedBlueGains_) -+ std::swap(params.gainR, params.gainB); -+ - for (unsigned int i = 0; i < kRGBLookupSize; i++) { - constexpr unsigned int div = - kRGBLookupSize * DebayerParams::kGain10 / kGammaLookupSize; -diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h -index fd1fa180..5f44fc65 100644 ---- a/src/libcamera/software_isp/debayer_cpu.h -+++ b/src/libcamera/software_isp/debayer_cpu.h -@@ -145,6 +145,7 @@ private: - unsigned int lineBufferIndex_; - unsigned int xShift_; /* Offset of 0/1 applied to window_.x */ - bool enableInputMemcpy_; -+ bool swapRedBlueGains_; - float gamma_correction_; - unsigned int measuredFrames_; - int64_t frameProcessTime_; --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0017-libcamera-Add-Software-ISP-benchmarking-documentatio.patch b/users/flokli/ipu6-softisp/libcamera/0017-libcamera-Add-Software-ISP-benchmarking-documentatio.patch deleted file mode 100644 index 2343e9c46fe8..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0017-libcamera-Add-Software-ISP-benchmarking-documentatio.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 6c509a3d144d46a11454d32d128d16e16602b50f Mon Sep 17 00:00:00 2001 -From: Hans de Goede <hdegoede@redhat.com> -Date: Mon, 11 Mar 2024 15:15:20 +0100 -Subject: [PATCH 17/21] libcamera: Add "Software ISP benchmarking" - documentation - -Add a "Software ISP benchmarking" documentation section which describes -the performance/power consumption measurements used during -the Software ISP's development. - -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> ---- - Documentation/index.rst | 1 + - Documentation/meson.build | 1 + - Documentation/software-isp-benchmarking.rst | 82 +++++++++++++++++++++ - 3 files changed, 84 insertions(+) - create mode 100644 Documentation/software-isp-benchmarking.rst - -diff --git a/Documentation/index.rst b/Documentation/index.rst -index 63fac72d..5442ae75 100644 ---- a/Documentation/index.rst -+++ b/Documentation/index.rst -@@ -24,3 +24,4 @@ - Lens driver requirements <lens_driver_requirements> - Python Bindings <python-bindings> - Camera Sensor Model <camera-sensor-model> -+ SoftwareISP Benchmarking <software-isp-benchmarking> -diff --git a/Documentation/meson.build b/Documentation/meson.build -index 7a58fec8..3872e0a8 100644 ---- a/Documentation/meson.build -+++ b/Documentation/meson.build -@@ -80,6 +80,7 @@ if sphinx.found() - 'lens_driver_requirements.rst', - 'python-bindings.rst', - 'sensor_driver_requirements.rst', -+ 'software-isp-benchmarking.rst', - '../README.rst', - ] - -diff --git a/Documentation/software-isp-benchmarking.rst b/Documentation/software-isp-benchmarking.rst -new file mode 100644 -index 00000000..b2803953 ---- /dev/null -+++ b/Documentation/software-isp-benchmarking.rst -@@ -0,0 +1,82 @@ -+.. SPDX-License-Identifier: CC-BY-SA-4.0 -+ -+.. _software-isp-benchmarking: -+ -+Software ISP benchmarking -+========================= -+ -+The Software ISP is particularly sensitive to performance regressions -+therefore it is a good idea to always benchmark the Software ISP -+before and after making changes to it and ensure that there are -+no performance regressions. -+ -+DebayerCpu class builtin benchmark -+---------------------------------- -+ -+The DebayerCpu class has a builtin benchmark. This benchmark -+measures the time spent on processing (collecting statistics -+and debayering) only, it does not measure the time spent on -+capturing or outputting the frames. -+ -+The builtin benchmark always runs. So this can be used by simply -+running "cam" or "qcam" with a pipeline using the Software ISP. -+ -+When it runs it will skip measuring the first 30 frames to -+allow the caches and the CPU temperature (turbo-ing) to warm-up -+and then it measures 30 fps and shows the total and per frame -+processing time using an info level log message: -+ -+.. code-block:: text -+ -+ INFO Debayer debayer_cpu.cpp:907 Processed 30 frames in 244317us, 8143 us/frame -+ -+To get stable measurements it is advised to disable any other processes which -+may cause significant CPU usage (e.g. disable wifi, bluetooth and browsers). -+When possible it is also advisable to disable CPU turbo-ing and -+frequency-scaling. -+ -+For example when benchmarking on a Lenovo ThinkPad X1 Yoga Gen 8, with -+the charger plugged in, the CPU can be fixed to run at 2 GHz using: -+ -+.. code-block:: shell -+ -+ sudo x86_energy_perf_policy --turbo-enable 0 -+ sudo cpupower frequency-set -d 2GHz -u 2GHz -+ -+with these settings the builtin bench reports a processing time of ~7.8ms/frame -+on this laptop for FHD SGRBG10 (unpacked) bayer data. -+ -+Measuring power consumption -+--------------------------- -+ -+Since the Software ISP is often used on mobile devices it is also -+important to measure power consumption and ensure that that does -+not regress. -+ -+For example to measure power consumption on a Lenovo ThinkPad X1 Yoga Gen 8 -+it needs to be running on battery and it should be configured with its -+platform-profile (/sys/firmware/acpi/platform_profile) set to balanced and -+with its default turbo and frequency-scaling behavior to match real world usage. -+ -+Then start qcam to capture a FHD picture at 30 fps and position the qcam window -+so that it is fully visible. After this run the following command to monitor -+the power consumption: -+ -+.. code-block:: shell -+ -+ watch -n 10 cat /sys/class/power_supply/BAT0/power_now /sys/class/hwmon/hwmon6/fan?_input -+ -+Note this not only measures the power consumption in µW it also monitors -+the speed of this laptop's 2 fans. This is important because depending on -+the ambient temperature the 2 fans may spin up while testing and this -+will cause an additional power consumption of approx. 0.5 W messing up -+the measurement. -+ -+After starting qcam + the watch command let the laptop sit without using -+it for 2 minutes for the readings to stabilize. Then check that the fans -+have not turned on and manually take a couple of consecutive power readings -+and avarage these. -+ -+On the example Lenovo ThinkPad X1 Yoga Gen 8 laptop this results in -+a measured power consumption of approx. 13 W while running qcam versus -+approx. 4-5 W while setting idle with its OLED panel on. --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0018-libcamera-software_isp-Apply-black-level-compensatio.patch b/users/flokli/ipu6-softisp/libcamera/0018-libcamera-software_isp-Apply-black-level-compensatio.patch deleted file mode 100644 index c746b74dba67..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0018-libcamera-software_isp-Apply-black-level-compensatio.patch +++ /dev/null @@ -1,396 +0,0 @@ -From bb608d177135d74e3c98b8a61fb459ebe254bca5 Mon Sep 17 00:00:00 2001 -From: Milan Zamazal <mzamazal@redhat.com> -Date: Mon, 11 Mar 2024 15:15:21 +0100 -Subject: [PATCH 18/21] libcamera: software_isp: Apply black level compensation - -Black may not be represented as 0 pixel value for given hardware, it may be -higher. If this is not compensated then various problems may occur such as low -contrast or suboptimal exposure. - -The black pixel value can be either retrieved from a tuning file for the given -hardware, or automatically on fly. The former is the right and correct method, -while the latter can be used when a tuning file is not available for the given -hardware. Since there is currently no support for tuning files in software ISP, -the automatic, hardware independent way, is always used. Support for tuning -files should be added in future but it will require more work than this patch. - -The patch looks at the image histogram and assumes that black starts when pixel -values start occurring on the left. A certain amount of the darkest pixels is -ignored; it doesn't matter whether they represent various kinds of noise or are -real, they are better to omit in any case to make the image looking better. It -also doesn't matter whether the darkest pixels occur around the supposed black -level or are spread between 0 and the black level, the difference is not -important. - -An arbitrary threshold of 2% darkest pixels is applied; there is no magic about -that value. - -The patch assumes that the black values for different colors are the same and -doesn't attempt any other non-primitive enhancements. It cannot completely -replace tuning files and simplicity, while providing visible benefit, is its -goal. Anything more sophisticated is left for future patches. - -A possible cheap enhancement, if needed, could be setting exposure + gain to -minimum values temporarily, before setting the black level. In theory, the -black level should be fixed but it may not be reached in all images. For this -reason, the patch updates black level only if the observed value is lower than -the current one; it should be never increased. - -The purpose of the patch is to compensate for hardware properties. General -image contrast enhancements are out of scope of this patch. - -Stats are still gathered as an uncorrected histogram, to avoid any confusion and -to represent the raw image data. Exposure must be determined after the black -level correction -- it has no influence on the sub-black area and must be -correct after applying the black level correction. The granularity of the -histogram is increased from 16 to 64 to provide a better precision (there is no -theory behind either of those numbers). - -Reviewed-by: Hans de Goede <hdegoede@redhat.com> -Signed-off-by: Milan Zamazal <mzamazal@redhat.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - .../internal/software_isp/debayer_params.h | 4 + - .../internal/software_isp/swisp_stats.h | 10 ++- - src/ipa/simple/black_level.cpp | 86 +++++++++++++++++++ - src/ipa/simple/black_level.h | 28 ++++++ - src/ipa/simple/meson.build | 7 +- - src/ipa/simple/soft_simple.cpp | 28 ++++-- - src/libcamera/software_isp/debayer_cpu.cpp | 13 ++- - src/libcamera/software_isp/debayer_cpu.h | 1 + - src/libcamera/software_isp/software_isp.cpp | 2 +- - 9 files changed, 162 insertions(+), 17 deletions(-) - create mode 100644 src/ipa/simple/black_level.cpp - create mode 100644 src/ipa/simple/black_level.h - -diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h -index 98965fa1..5e38e08b 100644 ---- a/include/libcamera/internal/software_isp/debayer_params.h -+++ b/include/libcamera/internal/software_isp/debayer_params.h -@@ -43,6 +43,10 @@ struct DebayerParams { - * \brief Gamma correction, 1.0 is no correction - */ - float gamma; -+ /** -+ * \brief Level of the black point, 0..255, 0 is no correction. -+ */ -+ unsigned int blackLevel; - }; - - } /* namespace libcamera */ -diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h -index afe42c9a..25cd5abd 100644 ---- a/include/libcamera/internal/software_isp/swisp_stats.h -+++ b/include/libcamera/internal/software_isp/swisp_stats.h -@@ -7,6 +7,8 @@ - - #pragma once - -+#include <array> -+ - namespace libcamera { - - /** -@@ -28,11 +30,15 @@ struct SwIspStats { - /** - * \brief Number of bins in the yHistogram. - */ -- static constexpr unsigned int kYHistogramSize = 16; -+ static constexpr unsigned int kYHistogramSize = 64; -+ /** -+ * \brief Type of the histogram. -+ */ -+ using histogram = std::array<unsigned int, kYHistogramSize>; - /** - * \brief A histogram of luminance values. - */ -- std::array<unsigned int, kYHistogramSize> yHistogram; -+ histogram yHistogram; - }; - - } /* namespace libcamera */ -diff --git a/src/ipa/simple/black_level.cpp b/src/ipa/simple/black_level.cpp -new file mode 100644 -index 00000000..8d52201b ---- /dev/null -+++ b/src/ipa/simple/black_level.cpp -@@ -0,0 +1,86 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2024, Red Hat Inc. -+ * -+ * black_level.cpp - black level handling -+ */ -+ -+#include "black_level.h" -+ -+#include <numeric> -+ -+#include <libcamera/base/log.h> -+ -+namespace libcamera { -+ -+LOG_DEFINE_CATEGORY(IPASoftBL) -+ -+/** -+ * \class BlackLevel -+ * \brief Object providing black point level for software ISP -+ * -+ * Black level can be provided in hardware tuning files or, if no tuning file is -+ * available for the given hardware, guessed automatically, with less accuracy. -+ * As tuning files are not yet implemented for software ISP, BlackLevel -+ * currently provides only guessed black levels. -+ * -+ * This class serves for tracking black level as a property of the underlying -+ * hardware, not as means of enhancing a particular scene or image. -+ * -+ * The class is supposed to be instantiated for the given camera stream. -+ * The black level can be retrieved using BlackLevel::get() method. It is -+ * initially 0 and may change when updated using BlackLevel::update() method. -+ */ -+ -+BlackLevel::BlackLevel() -+ : blackLevel_(255), blackLevelSet_(false) -+{ -+} -+ -+/** -+ * \brief Return the current black level -+ * -+ * \return The black level, in the range from 0 (minimum) to 255 (maximum). -+ * If the black level couldn't be determined yet, return 0. -+ */ -+unsigned int BlackLevel::get() const -+{ -+ return blackLevelSet_ ? blackLevel_ : 0; -+} -+ -+/** -+ * \brief Update black level from the provided histogram -+ * \param[in] yHistogram The histogram to be used for updating black level -+ * -+ * The black level is property of the given hardware, not image. It is updated -+ * only if it has not been yet set or if it is lower than the lowest value seen -+ * so far. -+ */ -+void BlackLevel::update(SwIspStats::histogram &yHistogram) -+{ -+ // The constant is selected to be "good enough", not overly conservative or -+ // aggressive. There is no magic about the given value. -+ constexpr float ignoredPercentage_ = 0.02; -+ const unsigned int total = -+ std::accumulate(begin(yHistogram), end(yHistogram), 0); -+ const unsigned int pixelThreshold = ignoredPercentage_ * total; -+ const unsigned int currentBlackIdx = -+ blackLevel_ / (256 / SwIspStats::kYHistogramSize); -+ -+ for (unsigned int i = 0, seen = 0; -+ i < currentBlackIdx && i < SwIspStats::kYHistogramSize; -+ i++) { -+ seen += yHistogram[i]; -+ if (seen >= pixelThreshold) { -+ blackLevel_ = i * (256 / SwIspStats::kYHistogramSize); -+ blackLevelSet_ = true; -+ LOG(IPASoftBL, Debug) -+ << "Auto-set black level: " -+ << i << "/" << SwIspStats::kYHistogramSize -+ << " (" << 100 * (seen - yHistogram[i]) / total << "% below, " -+ << 100 * seen / total << "% at or below)"; -+ break; -+ } -+ }; -+} -+} // namespace libcamera -diff --git a/src/ipa/simple/black_level.h b/src/ipa/simple/black_level.h -new file mode 100644 -index 00000000..b3785db0 ---- /dev/null -+++ b/src/ipa/simple/black_level.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2024, Red Hat Inc. -+ * -+ * black_level.h - black level handling -+ */ -+ -+#pragma once -+ -+#include <array> -+ -+#include "libcamera/internal/software_isp/swisp_stats.h" -+ -+namespace libcamera { -+ -+class BlackLevel -+{ -+public: -+ BlackLevel(); -+ unsigned int get() const; -+ void update(std::array<unsigned int, SwIspStats::kYHistogramSize> &yHistogram); -+ -+private: -+ unsigned int blackLevel_; -+ bool blackLevelSet_; -+}; -+ -+} // namespace libcamera -diff --git a/src/ipa/simple/meson.build b/src/ipa/simple/meson.build -index 3e863db7..44b5f1d7 100644 ---- a/src/ipa/simple/meson.build -+++ b/src/ipa/simple/meson.build -@@ -2,8 +2,13 @@ - - ipa_name = 'ipa_soft_simple' - -+soft_simple_sources = files([ -+ 'soft_simple.cpp', -+ 'black_level.cpp', -+]) -+ - mod = shared_module(ipa_name, -- ['soft_simple.cpp', libcamera_generated_ipa_headers], -+ [soft_simple_sources, libcamera_generated_ipa_headers], - name_prefix : '', - include_directories : [ipa_includes, libipa_includes], - dependencies : libcamera_private, -diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp -index 312df4ba..ac027568 100644 ---- a/src/ipa/simple/soft_simple.cpp -+++ b/src/ipa/simple/soft_simple.cpp -@@ -22,6 +22,8 @@ - #include "libcamera/internal/software_isp/debayer_params.h" - #include "libcamera/internal/software_isp/swisp_stats.h" - -+#include "black_level.h" -+ - namespace libcamera { - - LOG_DEFINE_CATEGORY(IPASoft) -@@ -33,7 +35,8 @@ class IPASoftSimple : public ipa::soft::IPASoftInterface - public: - IPASoftSimple() - : params_(static_cast<DebayerParams *>(MAP_FAILED)), -- stats_(static_cast<SwIspStats *>(MAP_FAILED)), ignore_updates_(0) -+ stats_(static_cast<SwIspStats *>(MAP_FAILED)), -+ blackLevel_(BlackLevel()), ignore_updates_(0) - { - } - -@@ -63,6 +66,7 @@ private: - SharedFD fdParams_; - DebayerParams *params_; - SwIspStats *stats_; -+ BlackLevel blackLevel_; - - int32_t exposure_min_, exposure_max_; - int32_t again_min_, again_max_; -@@ -196,6 +200,10 @@ void IPASoftSimple::processStats(const ControlList &sensorControls) - params_->gainG = 256; - params_->gamma = 0.5; - -+ if (ignore_updates_ > 0) -+ blackLevel_.update(stats_->yHistogram); -+ params_->blackLevel = blackLevel_.get(); -+ - setIspParams.emit(0); - - /* -@@ -211,18 +219,19 @@ void IPASoftSimple::processStats(const ControlList &sensorControls) - * Calculate Mean Sample Value (MSV) according to formula from: - * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf - */ -- constexpr unsigned int yHistValsPerBin = -- SwIspStats::kYHistogramSize / kExposureBinsCount; -- constexpr unsigned int yHistValsPerBinMod = -- SwIspStats::kYHistogramSize / -- (SwIspStats::kYHistogramSize % kExposureBinsCount + 1); -+ const unsigned int blackLevelHistIdx = -+ params_->blackLevel / (256 / SwIspStats::kYHistogramSize); -+ const unsigned int histogramSize = SwIspStats::kYHistogramSize - blackLevelHistIdx; -+ const unsigned int yHistValsPerBin = histogramSize / kExposureBinsCount; -+ const unsigned int yHistValsPerBinMod = -+ histogramSize / (histogramSize % kExposureBinsCount + 1); - int ExposureBins[kExposureBinsCount] = {}; - unsigned int denom = 0; - unsigned int num = 0; - -- for (unsigned int i = 0; i < SwIspStats::kYHistogramSize; i++) { -+ for (unsigned int i = 0; i < histogramSize; i++) { - unsigned int idx = (i - (i / yHistValsPerBinMod)) / yHistValsPerBin; -- ExposureBins[idx] += stats_->yHistogram[i]; -+ ExposureBins[idx] += stats_->yHistogram[blackLevelHistIdx + i]; - } - - for (unsigned int i = 0; i < kExposureBinsCount; i++) { -@@ -256,7 +265,8 @@ void IPASoftSimple::processStats(const ControlList &sensorControls) - - LOG(IPASoft, Debug) << "exposureMSV " << exposureMSV - << " exp " << exposure_ << " again " << again_ -- << " gain R/B " << params_->gainR << "/" << params_->gainB; -+ << " gain R/B " << params_->gainR << "/" << params_->gainB -+ << " black level " << params_->blackLevel; - } - - void IPASoftSimple::updateExposure(double exposureMSV) -diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp -index a1692693..3be3cdfe 100644 ---- a/src/libcamera/software_isp/debayer_cpu.cpp -+++ b/src/libcamera/software_isp/debayer_cpu.cpp -@@ -35,7 +35,7 @@ namespace libcamera { - * \param[in] stats Pointer to the stats object to use. - */ - DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats) -- : stats_(std::move(stats)), gamma_correction_(1.0) -+ : stats_(std::move(stats)), gamma_correction_(1.0), blackLevel_(0) - { - #ifdef __x86_64__ - enableInputMemcpy_ = false; -@@ -683,11 +683,16 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams - } - - /* Apply DebayerParams */ -- if (params.gamma != gamma_correction_) { -- for (unsigned int i = 0; i < kGammaLookupSize; i++) -- gamma_[i] = UINT8_MAX * powf(i / (kGammaLookupSize - 1.0), params.gamma); -+ if (params.gamma != gamma_correction_ || params.blackLevel != blackLevel_) { -+ const unsigned int blackIndex = -+ params.blackLevel * kGammaLookupSize / 256; -+ std::fill(gamma_.begin(), gamma_.begin() + blackIndex, 0); -+ const float divisor = kGammaLookupSize - blackIndex - 1.0; -+ for (unsigned int i = blackIndex; i < kGammaLookupSize; i++) -+ gamma_[i] = UINT8_MAX * powf((i - blackIndex) / divisor, params.gamma); - - gamma_correction_ = params.gamma; -+ blackLevel_ = params.blackLevel; - } - - if (swapRedBlueGains_) -diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h -index 5f44fc65..ea02f909 100644 ---- a/src/libcamera/software_isp/debayer_cpu.h -+++ b/src/libcamera/software_isp/debayer_cpu.h -@@ -147,6 +147,7 @@ private: - bool enableInputMemcpy_; - bool swapRedBlueGains_; - float gamma_correction_; -+ unsigned int blackLevel_; - unsigned int measuredFrames_; - int64_t frameProcessTime_; - /* Skip 30 frames for things to stabilize then measure 30 frames */ -diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp -index 388b4496..9b49be41 100644 ---- a/src/libcamera/software_isp/software_isp.cpp -+++ b/src/libcamera/software_isp/software_isp.cpp -@@ -64,7 +64,7 @@ LOG_DEFINE_CATEGORY(SoftwareIsp) - */ - SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls) - : debayer_(nullptr), -- debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10, DebayerParams::kGain10, 0.5f }, -+ debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10, DebayerParams::kGain10, 0.5f, 0 }, - dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System) - { - if (!dmaHeap_.isValid()) { --- -2.43.2 - diff --git a/users/flokli/ipu6-softisp/libcamera/0019-libcamera-Soft-IPA-use-CameraSensorHelper-for-analog.patch b/users/flokli/ipu6-softisp/libcamera/0019-libcamera-Soft-IPA-use-CameraSensorHelper-for-analog.patch deleted file mode 100644 index 5b562c603c52..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0019-libcamera-Soft-IPA-use-CameraSensorHelper-for-analog.patch +++ /dev/null @@ -1,239 +0,0 @@ -From b0c07674abecb05dc0af93a4b749971f057bc3c6 Mon Sep 17 00:00:00 2001 -From: Andrei Konovalov <andrey.konovalov.ynk@gmail.com> -Date: Mon, 11 Mar 2024 15:15:22 +0100 -Subject: [PATCH 19/21] libcamera: Soft IPA: use CameraSensorHelper for - analogue gain - -Use CameraSensorHelper to convert the analogue gain code read from the -camera sensor into real analogue gain value. In the future this makes -it possible to use faster AE/AGC algorithm. For now the same AE/AGC -algorithm is used, but even then the CameraSensorHelper lets us use the -full range of analogue gain values. - -If there is no CameraSensorHelper for the camera sensor in use, a -warning log message is printed, and the AE/AGC works exactly as before -this change. - -Signed-off-by: Andrei Konovalov <andrey.konovalov.ynk@gmail.com> -Reviewed-by: Hans de Goede <hdegoede@redhat.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Reviewed-by: Milan Zamazal <mzamazal@redhat.com> ---- - .../internal/software_isp/software_isp.h | 3 +- - src/ipa/simple/soft_simple.cpp | 77 ++++++++++++------- - src/libcamera/pipeline/simple/simple.cpp | 2 +- - src/libcamera/software_isp/software_isp.cpp | 8 +- - 4 files changed, 57 insertions(+), 33 deletions(-) - -diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h -index 8d25e979..2a6db7ba 100644 ---- a/include/libcamera/internal/software_isp/software_isp.h -+++ b/include/libcamera/internal/software_isp/software_isp.h -@@ -26,6 +26,7 @@ - #include <libcamera/ipa/soft_ipa_interface.h> - #include <libcamera/ipa/soft_ipa_proxy.h> - -+#include "libcamera/internal/camera_sensor.h" - #include "libcamera/internal/dma_heaps.h" - #include "libcamera/internal/pipeline_handler.h" - #include "libcamera/internal/shared_mem_object.h" -@@ -43,7 +44,7 @@ LOG_DECLARE_CATEGORY(SoftwareIsp) - class SoftwareIsp - { - public: -- SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls); -+ SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor); - ~SoftwareIsp(); - - int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; } -diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp -index ac027568..e4d64762 100644 ---- a/src/ipa/simple/soft_simple.cpp -+++ b/src/ipa/simple/soft_simple.cpp -@@ -22,6 +22,8 @@ - #include "libcamera/internal/software_isp/debayer_params.h" - #include "libcamera/internal/software_isp/swisp_stats.h" - -+#include "libipa/camera_sensor_helper.h" -+ - #include "black_level.h" - - namespace libcamera { -@@ -67,18 +69,27 @@ private: - DebayerParams *params_; - SwIspStats *stats_; - BlackLevel blackLevel_; -+ std::unique_ptr<CameraSensorHelper> camHelper_; - - int32_t exposure_min_, exposure_max_; -- int32_t again_min_, again_max_; -- int32_t again_, exposure_; -+ int32_t exposure_; -+ double again_min_, again_max_, againMinStep_; -+ double again_; - unsigned int ignore_updates_; - }; - --int IPASoftSimple::init([[maybe_unused]] const IPASettings &settings, -+int IPASoftSimple::init(const IPASettings &settings, - const SharedFD &fdStats, - const SharedFD &fdParams, - const ControlInfoMap &sensorInfoMap) - { -+ camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel); -+ if (camHelper_ == nullptr) { -+ LOG(IPASoft, Warning) -+ << "Failed to create camera sensor helper for " -+ << settings.sensorModel; -+ } -+ - fdStats_ = fdStats; - if (!fdStats_.isValid()) { - LOG(IPASoft, Error) << "Invalid Statistics handle"; -@@ -132,25 +143,35 @@ int IPASoftSimple::configure(const ControlInfoMap &sensorInfoMap) - exposure_min_ = 1; - } - -- again_min_ = gain_info.min().get<int32_t>(); -- again_max_ = gain_info.max().get<int32_t>(); -- /* -- * The camera sensor gain (g) is usually not equal to the value written -- * into the gain register (x). But the way how the AGC algorithm changes -- * the gain value to make the total exposure closer to the optimum assumes -- * that g(x) is not too far from linear function. If the minimal gain is 0, -- * the g(x) is likely to be far from the linear, like g(x) = a / (b * x + c). -- * To avoid unexpected changes to the gain by the AGC algorithm (abrupt near -- * one edge, and very small near the other) we limit the range of the gain -- * values used. -- */ -- if (!again_min_) { -- LOG(IPASoft, Warning) << "Minimum gain is zero, that can't be linear"; -- again_min_ = std::min(100, again_min_ / 2 + again_max_ / 2); -+ int32_t again_min = gain_info.min().get<int32_t>(); -+ int32_t again_max = gain_info.max().get<int32_t>(); -+ -+ if (camHelper_) { -+ again_min_ = camHelper_->gain(again_min); -+ again_max_ = camHelper_->gain(again_max); -+ againMinStep_ = (again_max_ - again_min_) / 100.0; -+ } else { -+ /* -+ * The camera sensor gain (g) is usually not equal to the value written -+ * into the gain register (x). But the way how the AGC algorithm changes -+ * the gain value to make the total exposure closer to the optimum assumes -+ * that g(x) is not too far from linear function. If the minimal gain is 0, -+ * the g(x) is likely to be far from the linear, like g(x) = a / (b * x + c). -+ * To avoid unexpected changes to the gain by the AGC algorithm (abrupt near -+ * one edge, and very small near the other) we limit the range of the gain -+ * values used. -+ */ -+ again_max_ = again_max; -+ if (!again_min) { -+ LOG(IPASoft, Warning) << "Minimum gain is zero, that can't be linear"; -+ again_min_ = std::min(100, again_min / 2 + again_max / 2); -+ } -+ againMinStep_ = 1.0; - } - - LOG(IPASoft, Info) << "Exposure " << exposure_min_ << "-" << exposure_max_ -- << ", gain " << again_min_ << "-" << again_max_; -+ << ", gain " << again_min_ << "-" << again_max_ -+ << " (" << againMinStep_ << ")"; - - return 0; - } -@@ -252,12 +273,14 @@ void IPASoftSimple::processStats(const ControlList &sensorControls) - ControlList ctrls(sensorControls); - - exposure_ = ctrls.get(V4L2_CID_EXPOSURE).get<int32_t>(); -- again_ = ctrls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>(); -+ int32_t again = ctrls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>(); -+ again_ = camHelper_ ? camHelper_->gain(again) : again; - - updateExposure(exposureMSV); - - ctrls.set(V4L2_CID_EXPOSURE, exposure_); -- ctrls.set(V4L2_CID_ANALOGUE_GAIN, again_); -+ ctrls.set(V4L2_CID_ANALOGUE_GAIN, -+ static_cast<int32_t>(camHelper_ ? camHelper_->gainCode(again_) : again_)); - - ignore_updates_ = 2; - -@@ -276,7 +299,7 @@ void IPASoftSimple::updateExposure(double exposureMSV) - static constexpr uint8_t kExpNumeratorUp = kExpDenominator + 1; - static constexpr uint8_t kExpNumeratorDown = kExpDenominator - 1; - -- int next; -+ double next; - - if (exposureMSV < kExposureOptimal - kExposureSatisfactory) { - next = exposure_ * kExpNumeratorUp / kExpDenominator; -@@ -286,18 +309,18 @@ void IPASoftSimple::updateExposure(double exposureMSV) - exposure_ = next; - if (exposure_ >= exposure_max_) { - next = again_ * kExpNumeratorUp / kExpDenominator; -- if (next - again_ < 1) -- again_ += 1; -+ if (next - again_ < againMinStep_) -+ again_ += againMinStep_; - else - again_ = next; - } - } - - if (exposureMSV > kExposureOptimal + kExposureSatisfactory) { -- if (exposure_ == exposure_max_ && again_ != again_min_) { -+ if (exposure_ == exposure_max_ && again_ > again_min_) { - next = again_ * kExpNumeratorDown / kExpDenominator; -- if (again_ - next < 1) -- again_ -= 1; -+ if (again_ - next < againMinStep_) -+ again_ -= againMinStep_; - else - again_ = next; - } else { -diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp -index c3ebb7b7..7e932a14 100644 ---- a/src/libcamera/pipeline/simple/simple.cpp -+++ b/src/libcamera/pipeline/simple/simple.cpp -@@ -525,7 +525,7 @@ int SimpleCameraData::init() - * Instantiate Soft ISP if this is enabled for the given driver and no converter is used. - */ - if (!converter_ && pipe->swIspEnabled()) { -- swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_->controls()); -+ swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_.get()); - if (!swIsp_->isValid()) { - LOG(SimplePipeline, Warning) - << "Failed to create software ISP, disabling software debayering"; -diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp -index 9b49be41..ea4d96e4 100644 ---- a/src/libcamera/software_isp/software_isp.cpp -+++ b/src/libcamera/software_isp/software_isp.cpp -@@ -60,9 +60,9 @@ LOG_DEFINE_CATEGORY(SoftwareIsp) - /** - * \brief Constructs SoftwareIsp object - * \param[in] pipe The pipeline handler in use -- * \param[in] sensorControls ControlInfoMap describing the controls supported by the sensor -+ * \param[in] sensor Pointer to the CameraSensor instance owned by the pipeline handler - */ --SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls) -+SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor) - : debayer_(nullptr), - debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10, DebayerParams::kGain10, 0.5f, 0 }, - dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System) -@@ -97,10 +97,10 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorCont - return; - } - -- int ret = ipa_->init(IPASettings{ "No cfg file", "No sensor model" }, -+ int ret = ipa_->init(IPASettings{ "No cfg file", sensor->model() }, - debayer_->getStatsFD(), - sharedParams_.fd(), -- sensorControls); -+ sensor->controls()); - if (ret) { - LOG(SoftwareIsp, Error) << "IPA init failed"; - debayer_.reset(); --- -2.43.2 - |