From patchwork Thu Dec 14 12:13:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19316 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id F2C2DBD87C for ; Thu, 14 Dec 2023 12:13:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id ADA5C62B3E; Thu, 14 Dec 2023 13:13:59 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556039; bh=9lAdjEGb84KrawF6VpzD8e4nEnFR/pZ0hxGDAoDEsKc=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=yd63Nl3NoBRn7xIF3U14KxCoKZ2hiSQ2LgmNG3pUcMBp8SwJUuFcul4hBrlrXDxdQ uS7sN6oDZgZHXmN2bMs6FxOQo0zk0hcbMIGyesG7sVIOcwOgY0yDFGYA1yjMwpQuuw 17bMVd/EFOp/eWE8JB9HFDBITJ7iSIzOKV8YqEOhvHkhDH9Mo7uEgqxpLdmbHpQm6Q PKnUDJ4XIXuMU1+odwPFepzjEcWPAkZWrc04k7aWVuLacqwe6UtFoRVJyS+X6sntfu 16LVGTY9hHUXWcqPhy6cK9jR+tvigT5OBhAiigQQUG9fB6eHCiWOw5jl+Un+iQezNx 9RUpkWywn4dpw== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4C5B261D97 for ; Thu, 14 Dec 2023 13:13:58 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="cuQGl5T7"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556037; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=W1QTcMYwG8Wi8q3OEBBjijsdZNeRjmeL4rPymXzB/3A=; b=cuQGl5T7nklwwqEL+Cc47TD+3IQ3QX000S5OkxVxD1VR3U6+rfSNXW+QdSpPWrU27o5CHb E75WIFGD4PgX/QKRX86RyV+Qew76HT/9Vxcv1oAC6qW5yAUwdHqWXD6pRFhXwMIdID4KV0 3RaHDiUzlqxOx/hTv98RYnqsmJVO9zk= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-644-OkcUAu_-MFWkLPgsDDzZGA-1; Thu, 14 Dec 2023 07:13:54 -0500 X-MC-Unique: OkcUAu_-MFWkLPgsDDzZGA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 944BD85A58A; Thu, 14 Dec 2023 12:13:53 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4E36D1121306; Thu, 14 Dec 2023 12:13:52 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:39 +0100 Message-ID: <20231214121350.206015-2-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 01/11] libcamera: introduce SoftwareIsp class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Andrey Konovalov Signed-off-by: Andrey Konovalov --- include/libcamera/internal/meson.build | 1 + include/libcamera/internal/software_isp.h | 109 ++++++++++++++++++++++ src/libcamera/meson.build | 1 + src/libcamera/software_isp.cpp | 62 ++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 include/libcamera/internal/software_isp.h create mode 100644 src/libcamera/software_isp.cpp diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 7f1f3440..0f725cfd 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -38,6 +38,7 @@ libcamera_internal_headers = files([ 'process.h', 'pub_key.h', 'request.h', + 'software_isp.h', 'source_paths.h', 'sysfs.h', 'v4l2_device.h', diff --git a/include/libcamera/internal/software_isp.h b/include/libcamera/internal/software_isp.h new file mode 100644 index 00000000..49cf7968 --- /dev/null +++ b/include/libcamera/internal/software_isp.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * + * software_isp.h - Interface for a software implementation of an ISP + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "libcamera/internal/pipeline_handler.h" + +namespace libcamera { + +class FrameBuffer; +class PixelFormat; +struct StreamConfiguration; + +LOG_DECLARE_CATEGORY(SoftwareIsp) + +class SoftwareIsp +{ +public: + SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls); + virtual ~SoftwareIsp(); + + virtual int loadConfiguration(const std::string &filename) = 0; + + virtual bool isValid() const = 0; + + virtual std::vector formats(PixelFormat input) = 0; + virtual SizeRange sizes(PixelFormat inputFormat, const Size &inputSize) = 0; + + virtual std::tuple + strideAndFrameSize(const PixelFormat &pixelFormat, const Size &size) = 0; + + virtual int configure(const StreamConfiguration &inputCfg, + const std::vector> &outputCfgs) = 0; + virtual int exportBuffers(unsigned int output, unsigned int count, + std::vector> *buffers) = 0; + + virtual int start() = 0; + virtual void stop() = 0; + + virtual int queueBuffers(FrameBuffer *input, + const std::map &outputs) = 0; + + virtual void processStats(const ControlList &sensorControls) = 0; // rather merge with queueBuffers()? + + virtual Signal &getSignalSetSensorControls() = 0; + + Signal inputBufferReady; + Signal outputBufferReady; + + /* The int parameter isn't actually used */ + Signal ispStatsReady; +}; + +class SoftwareIspFactoryBase +{ +public: + SoftwareIspFactoryBase(); + virtual ~SoftwareIspFactoryBase() = default; + + static std::unique_ptr create(PipelineHandler *pipe, + const ControlInfoMap &sensorControls); + static SoftwareIspFactoryBase *&factory(); + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(SoftwareIspFactoryBase) + + static void registerType(SoftwareIspFactoryBase *factory); + virtual std::unique_ptr createInstance(PipelineHandler *pipe, + const ControlInfoMap &sensorControls) const = 0; +}; + +template +class SoftwareIspFactory : public SoftwareIspFactoryBase +{ +public: + SoftwareIspFactory() + : SoftwareIspFactoryBase() + { + } + + std::unique_ptr createInstance(PipelineHandler *pipe, + const ControlInfoMap &sensorControls) const override + { + return std::make_unique<_SoftwareIsp>(pipe, sensorControls); + } +}; + +#define REGISTER_SOFTWAREISP(softwareIsp) \ + static SoftwareIspFactory global_##softwareIsp##Factory; + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 45f63e93..b3606969 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -40,6 +40,7 @@ libcamera_sources = files([ 'process.cpp', 'pub_key.cpp', 'request.cpp', + 'software_isp.cpp', 'source_paths.cpp', 'stream.cpp', 'sysfs.cpp', diff --git a/src/libcamera/software_isp.cpp b/src/libcamera/software_isp.cpp new file mode 100644 index 00000000..2ff97d70 --- /dev/null +++ b/src/libcamera/software_isp.cpp @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * + * software_isp.cpp - Interface for a software implementation of an ISP + */ + +#include "libcamera/internal/software_isp.h" + +#include + +namespace libcamera { + +LOG_DEFINE_CATEGORY(SoftwareIsp) + +SoftwareIsp::SoftwareIsp([[maybe_unused]] PipelineHandler *pipe, + [[maybe_unused]] const ControlInfoMap &sensorControls) +{ +} + +SoftwareIsp::~SoftwareIsp() +{ +} + +/* SoftwareIspFactoryBase */ + +SoftwareIspFactoryBase::SoftwareIspFactoryBase() +{ + registerType(this); +} + +void SoftwareIspFactoryBase::registerType(SoftwareIspFactoryBase *factory) +{ + SoftwareIspFactoryBase *®istered = + SoftwareIspFactoryBase::factory(); + + ASSERT(!registered && factory); + registered = factory; +} + +SoftwareIspFactoryBase *&SoftwareIspFactoryBase::factory() +{ + static SoftwareIspFactoryBase *factory; + return factory; +} + +std::unique_ptr +SoftwareIspFactoryBase::create(PipelineHandler *pipe, + const ControlInfoMap &sensorControls) +{ + SoftwareIspFactoryBase *factory = SoftwareIspFactoryBase::factory(); + if (!factory) + return nullptr; + + std::unique_ptr swIsp = factory->createInstance(pipe, sensorControls); + if (swIsp->isValid()) + return swIsp; + + return nullptr; +} + +} /* namespace libcamera */ From patchwork Thu Dec 14 12:13:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19317 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id CDB5CBD87C for ; Thu, 14 Dec 2023 12:14:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 72C4162B41; Thu, 14 Dec 2023 13:14:02 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556042; bh=nkBUFGv3uyXbfkf/vAkDvT2vcORiVdyRrFYh89oaCzY=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=A+AH+PyK2+UesnQAJbJ15OugqN6igKUYlNfDLm01eUHMPzheLIGfSUdjtakN8NfdW m7mdn/HDXowyvIyCydi1bR6WJwDuvu5LE6IOEZbrJlxYF1Lt3NtM2Q6MLfobGIkMKt vn9NMG4uGmXJLopS0t+VkOuJKWlNMuS5k367FXXn059AFq+2XhkWhUlqH7UAdfmDju 9IVGzBhlq79OFzvtjd+I1GhFXg4o38isrx6t+JEPCLl+ZZQMOpirlHu7iVQeevEalv gKuPofBlfrP32WNg2Cg86g0Nz+BNzbxYQy+abLL4z84YN9Oy4m0P/Ov4eBqakdgggr ELnpQ9b3Uu1gA== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BD57662B30 for ; Thu, 14 Dec 2023 13:14:00 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="KBIJmmDE"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556039; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uPBQAeNBtp2CwgWQzaFfaPNEs0GvC5dQJbJuWIwzw+E=; b=KBIJmmDE1d347DDZX7Uajw/YU+OKYQhy4/m0vMnPL6wgBuREOwRRNCNh0EULntsnvk4IeU xnN72cljwKxoXEc5e35FF2GDBQ/KKbxN3a4DQv/YvsuU64NaQ7twC8oV1QBc35UOq7b5iC JdNRb0mzP8KPGLprYvWiUccCRDfaK5w= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-541-SKJDr3-zPdC63NonhaMryA-1; Thu, 14 Dec 2023 07:13:55 -0500 X-MC-Unique: SKJDr3-zPdC63NonhaMryA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 16BA21C05148; Thu, 14 Dec 2023 12:13:55 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id C5A391121306; Thu, 14 Dec 2023 12:13:53 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:40 +0100 Message-ID: <20231214121350.206015-3-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 02/11] libcamera: internal: Move SharedMemObject class to a common directory X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Andrey Konovalov Move SharedMemObject class out of RPi namespace and put it into include/libcamera/internal so that everyone could use it. Signed-off-by: Andrey Konovalov --- include/libcamera/internal/meson.build | 1 + .../common => include/libcamera/internal}/shared_mem_object.h | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) rename {src/libcamera/pipeline/rpi/common => include/libcamera/internal}/shared_mem_object.h (98%) diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 0f725cfd..b780777c 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -38,6 +38,7 @@ libcamera_internal_headers = files([ 'process.h', 'pub_key.h', 'request.h', + 'shared_mem_object.h', 'software_isp.h', 'source_paths.h', 'sysfs.h', diff --git a/src/libcamera/pipeline/rpi/common/shared_mem_object.h b/include/libcamera/internal/shared_mem_object.h similarity index 98% rename from src/libcamera/pipeline/rpi/common/shared_mem_object.h rename to include/libcamera/internal/shared_mem_object.h index aa56c220..bfb639ee 100644 --- a/src/libcamera/pipeline/rpi/common/shared_mem_object.h +++ b/include/libcamera/internal/shared_mem_object.h @@ -19,8 +19,6 @@ namespace libcamera { -namespace RPi { - template class SharedMemObject { @@ -123,6 +121,4 @@ private: T *obj_; }; -} /* namespace RPi */ - } /* namespace libcamera */ From patchwork Thu Dec 14 12:13:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19318 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 786A3C3292 for ; Thu, 14 Dec 2023 12:14:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1C92062B4A; Thu, 14 Dec 2023 13:14:04 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556044; bh=HGoZ/2miZ0DnzfXtEPZ5obtr5/e2y45lUGzw4o3mEBk=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=ctTbEcH9gBzCIx1tNsHEigeVS5r93uJBoNQN8Dakyv7+6fhwmfq6ad6/3wze6ECBY w8Uk870ODinN6hA/jIEIK5js5r+2WQY+sWwuipBSXe5kYemdPPkEhhx+C5OzlmY1Nm Bc17u1f/O4sJhzhgyC/tTXYTPNZ+ctlRAitJ7vIEPruYTvdfOmJeqvu6C8QsmjQssI 3zCCJhAkM5fgjuP+r98W1KXYw9uyhfORD7xxcR78msePnNc1Y56L9RzgBzAgVvbYHk KIxZtkgc6IYt5lWffIAog4a6G98E01d+1ZtLXw7sWf0v0cYNTpQZuzD/wyulrpbpZ7 uEny4TsftO0vg== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 15CB161D97 for ; Thu, 14 Dec 2023 13:14:02 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="h8LRWqQ1"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556041; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jb1x2doyAt9CwBVHIyjwa9LcY/h0jg/Vb4MkHLGfX6I=; b=h8LRWqQ1Wbt20VBMgvT4oopmd6ZyRs9/sNfIlMKVQPa4Cuwtn0MG96Yb/IZnrldzM/SnNf R5M9pmgWU2zKlTwrJ9FUiMmpj5eVJLT13HcOwlb9BF15jWaGtqsbAyFLVG+c+ER6+pUimZ YCh8DiLdU8D0yjfvmdEziDnx1+kNOSQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-637-rWsdU6djMhW3DP-oEIcReQ-1; Thu, 14 Dec 2023 07:13:57 -0500 X-MC-Unique: rWsdU6djMhW3DP-oEIcReQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BBA538630C5; Thu, 14 Dec 2023 12:13:56 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id 481B31121306; Thu, 14 Dec 2023 12:13:55 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:41 +0100 Message-ID: <20231214121350.206015-4-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 03/11] libcamera: software_isp: Add SwStats base class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a virtual base class for CPU based software statistics gathering implementations. The idea is for the implementations to offer 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 base class also allows the user of an implementation to specify a window over which to gather statistics instead of processing the whole frame; and it allows the implementation to choose to only process 1/2, 1/4th, etc. of the lines instead of processing all lines (in the window) by setting y_skip_mask_ from configure(). Skipping columns is left up the line-processing functions provided by the implementation. The base class also provides a processFrame() convenience function which collects statistics for an entire frame at once for use cases where CPU based software debayering is not used. Co-authored-by: Andrey Konovalov Signed-off-by: Andrey Konovalov Signed-off-by: Hans de Goede --- .../internal/software_isp/meson.build | 6 + .../internal/software_isp/swisp_stats.h | 21 +++ .../libcamera/internal/software_isp/swstats.h | 150 ++++++++++++++++++ src/libcamera/software_isp/meson.build | 5 + src/libcamera/software_isp/swstats.cpp | 65 ++++++++ 5 files changed, 247 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 include/libcamera/internal/software_isp/swstats.h create mode 100644 src/libcamera/software_isp/meson.build create mode 100644 src/libcamera/software_isp/swstats.cpp diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build new file mode 100644 index 00000000..1c43acc4 --- /dev/null +++ b/include/libcamera/internal/software_isp/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: CC0-1.0 + +libcamera_internal_headers += files([ + 'swisp_stats.h', + 'swstats.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..f7afbaa4 --- /dev/null +++ b/include/libcamera/internal/software_isp/swisp_stats.h @@ -0,0 +1,21 @@ +/* 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 { + +struct SwIspStats { + unsigned long sumR_; + unsigned long sumB_; + unsigned long sumG_; + + float bright_ratio; + float too_bright_ratio; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/software_isp/swstats.h b/include/libcamera/internal/software_isp/swstats.h new file mode 100644 index 00000000..0e7407f6 --- /dev/null +++ b/include/libcamera/internal/software_isp/swstats.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * swstats.h - software statistics base class + */ + +#pragma once + +#include + +#include +#include + +#include + +namespace libcamera { + +class PixelFormat; +struct SharedFD; +struct StreamConfiguration; + +LOG_DECLARE_CATEGORY(SwStats) + +class SwStats +{ +public: + virtual ~SwStats() = 0; + + virtual bool isValid() const = 0; + + /* + * Setup the SwStats object for the passed in input format. + * Return 0 on success, a negative errno value on failure + * (unsupported format or failed to create the SharedMemObject). + */ + virtual int configure(const StreamConfiguration &inputCfg) = 0; + + /* Get the FD for the SharedMemObject for the stats. */ + virtual const SharedFD &getStatsFD() = 0; + +protected: + typedef void (SwStats::*statsProcessFn)(const uint8_t *src, unsigned int stride); + typedef void (SwStats::*statsVoidFn)(); + + /* Variables set by configure(), used every line */ + statsProcessFn stats0_; + statsProcessFn stats2_; + + unsigned int bpp_; /* Memory used per pixel, not precision */ + unsigned int y_skip_mask_; /* Skip lines where this bitmask is set in y */ + + /* Statistics windows, set by setWindow(), used every line */ + Rectangle window_; + + /* Variables set by configure(), used once per frame */ + statsVoidFn startFrame_; + statsVoidFn finishFrame_; + Size patternSize_; + unsigned int x_shift_; /* Offset of 0/1 applied to window_.x for bayer variants */ + +public: + /* + * 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. + */ + const Size &patternSize() { return patternSize_; } + + /* + * Specify window coordinates over which to gather statistics. + */ + void setWindow(Rectangle window) + { + window_ = window; + + window_.x &= ~(patternSize_.width - 1); + window_.x += x_shift_; + window_.y &= ~(patternSize_.height - 1); + + /* width_ - x_shift_ to make sure the window fits */ + window_.width -= x_shift_; + window_.width &= ~(patternSize_.width - 1); + window_.height &= ~(patternSize_.height - 1); + } + + /* + * Reset state to start statistic gathering for a new frame. + * This may only be called after a successful setWindow() call. + */ + void startFrame() + { + (this->*startFrame_)(); + } + + /* + * Process line 0 of input formats with patternSize height == 1. + * Process line 0 + 1 of input formats with patternSize height >= 2. + * This may only be called after a successful setWindow() call. + */ + void processLine0(unsigned int y, const uint8_t *src, unsigned int stride) + { + if ((y & y_skip_mask_) || y < (unsigned int)window_.y || + y >= (window_.y + window_.height)) + return; + + (this->*stats0_)(src + window_.x * bpp_ / 8, stride); + } + + /* + * Process lines 2 + 3 of input formats with patternSize height == 4. + * This may only be called after a successful setWindow() call. + */ + void processLine2(unsigned int y, const uint8_t *src, unsigned int stride) + { + if ((y & y_skip_mask_) || y < (unsigned int)window_.y || + y >= (window_.y + window_.height)) + return; + + (this->*stats2_)(src + window_.x * bpp_ / 8, stride); + } + + /* + * Finish statistics calculation for current frame and + * store the results in the SharedMemObject. + * This may only be called after a successful setWindow() call. + */ + void finishFrame() + { + (this->*finishFrame_)(); + } + + /* + * Process a whole frame at once, replacing manually calling + * startFrame() + processLine0() + finishFrame(). + * This may only be called after a successful setWindow() call. + */ + void processFrame(const uint8_t *src, unsigned int stride); + + /* The int parameter isn't actually used */ + Signal statsReady; +}; + +} /* namespace libcamera */ diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build new file mode 100644 index 00000000..9359075d --- /dev/null +++ b/src/libcamera/software_isp/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: CC0-1.0 + +libcamera_sources += files([ + 'swstats.cpp', +]) diff --git a/src/libcamera/software_isp/swstats.cpp b/src/libcamera/software_isp/swstats.cpp new file mode 100644 index 00000000..9a5e1a10 --- /dev/null +++ b/src/libcamera/software_isp/swstats.cpp @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * swstats.cpp - software statistics base class + */ + +#include "libcamera/internal/software_isp/swstats.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(SwStats) + +void SwStats::processFrame(const uint8_t *src, unsigned int stride) +{ + unsigned int y_end = window_.y + window_.height; + + startFrame(); + + /* Adjust src to point to starting corner of the statistics window */ + src += window_.y * stride; + src += window_.x * bpp_ / 8; + + switch (patternSize_.height) { + case 1: + for (unsigned int y = window_.y ; y < y_end; y++) { + if (!(y & y_skip_mask_)) + (this->*stats0_)(src, stride); + src += stride; + } + break; + case 2: + for (unsigned int y = window_.y ; y < y_end; y += 2) { + if (!(y & y_skip_mask_)) + (this->*stats0_)(src, stride); + src += 2 * stride; + } + break; + case 4: + for (unsigned int y = window_.y ; y < y_end; y += 4) { + if (y & y_skip_mask_) { + src += 4 * stride; + continue; + } + + (this->*stats0_)(src, stride); + src += 2 * stride; + (this->*stats2_)(src, stride); + src += 2 * stride; + } + break; + } + + finishFrame(); +} + +SwStats::~SwStats() +{ +} + +} /* namespace libcamera */ From patchwork Thu Dec 14 12:13:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19319 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id F1249BD87C for ; Thu, 14 Dec 2023 12:14:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 936DA62B58; Thu, 14 Dec 2023 13:14:06 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556046; bh=wzZtq87pwIp4bkDwv99FE+gohvDyk6GlJxITW4iDdh8=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=HbZvufE3ug2Dtga1XoTJJJyl1ISAE6DAKMRRHPuGIyDmo4nA1MLOOHC0i6damns1d DTpUdjHMA28v6+cF0lHobPvysPJ7FO9E97dZFiQjXR/4AQ1RK3VwRAHWmga2T9WVGz wuhhOT2nsg2Z74RyIVEDrq0NtCjZwDCXxZLOyNVhyJG2Es3aqtRHET19cMsDf9EQXp kjkDHe29zkhvsBWmpVwwasKHy9TLiecXTIDJTVMyrVfHIBD8sxARFedlRAHwXXKCCl pJaGzsyU6B9Qz5v6xsJFYRgRU/PUyctRsKmwOcQA7jERvjFOp2TUREVq0K0j5U0WuR YawlV1mQVK2qQ== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 20E1C62B52 for ; Thu, 14 Dec 2023 13:14:04 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="T/k+kqD9"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556043; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dWnOKmi+sc5buSYcLiTXGs4X2NRo61ufepPWcmP87vM=; b=T/k+kqD9sfmgJ6Jfv9Yd2XAVUIHpJmnuNmJRlrf6c3mlXlxceqSTQ1mkEefGWaPzxbl9RD wjp87iTU5iftQTi9UGHUUeOCavIFKPC+nvnJSuqnXqX5rQbrRQht+XgvPxZkt5nYk5SKBc qcX79EsSeVEiOsFl24KLKKomIJLDpEs= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-561-ubUzBS2MNyar7QWjPNJQIg-1; Thu, 14 Dec 2023 07:13:58 -0500 X-MC-Unique: ubUzBS2MNyar7QWjPNJQIg-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 5DD4E848C07; Thu, 14 Dec 2023 12:13:58 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id ECD581121306; Thu, 14 Dec 2023 12:13:56 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:42 +0100 Message-ID: <20231214121350.206015-5-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 04/11] libcamera: software_isp: Add SwStatsCpu class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Pavel Machek , Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a CPU based SwStats implementation for SoftwareISP / SoftIPA use. Co-authored-by: Andrey Konovalov Signed-off-by: Andrey Konovalov Suggested-by: Pavel Machek Signed-off-by: Pavel Machek Signed-off-by: Hans de Goede --- .../internal/software_isp/meson.build | 1 + .../internal/software_isp/swstats_cpu.h | 46 +++++ src/libcamera/software_isp/meson.build | 1 + src/libcamera/software_isp/swstats_cpu.cpp | 169 ++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 include/libcamera/internal/software_isp/swstats_cpu.h create mode 100644 src/libcamera/software_isp/swstats_cpu.cpp diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build index 1c43acc4..1d9e4018 100644 --- a/include/libcamera/internal/software_isp/meson.build +++ b/include/libcamera/internal/software_isp/meson.build @@ -3,4 +3,5 @@ libcamera_internal_headers += files([ 'swisp_stats.h', 'swstats.h', + 'swstats_cpu.h', ]) diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h new file mode 100644 index 00000000..0ceb995f --- /dev/null +++ b/include/libcamera/internal/software_isp/swstats_cpu.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * swstats_cpu.h - CPU based software statistics implementation + */ + +#pragma once + +#include "libcamera/internal/shared_mem_object.h" +#include "libcamera/internal/software_isp/swisp_stats.h" +#include "libcamera/internal/software_isp/swstats.h" + +namespace libcamera { + +class SwStatsCpu : public SwStats +{ +public: + SwStatsCpu(); + ~SwStatsCpu() { } + + bool isValid() const { return sharedStats_.fd().isValid(); } + const SharedFD &getStatsFD() { return sharedStats_.fd(); } + int configure(const StreamConfiguration &inputCfg); + /* FIXME this should be dropped once AWB has moved to the IPA */ + SwIspStats getStats() { return *sharedStats_; } +private: + void statsBGGR10PLine0(const uint8_t *src, unsigned int stride); + void statsGBRG10PLine0(const uint8_t *src, unsigned int stride); + void statsGRBG10PLine0(const uint8_t *src, unsigned int stride); + void statsRGGB10PLine0(const uint8_t *src, unsigned int stride); + void resetStats(void); + void finishStats(void); + + SharedMemObject sharedStats_; + SwIspStats stats_; + + unsigned int bright_sum_; + unsigned int too_bright_sum_; +}; + +} /* namespace libcamera */ diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build index 9359075d..d31c6217 100644 --- a/src/libcamera/software_isp/meson.build +++ b/src/libcamera/software_isp/meson.build @@ -2,4 +2,5 @@ libcamera_sources += files([ 'swstats.cpp', + '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..15f23953 --- /dev/null +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * swstats_cpu.cpp - CPU based software statistics implementation + */ + +#include "libcamera/internal/software_isp/swstats_cpu.h" + +#include + +#include + +#include "libcamera/internal/bayer_format.h" + +namespace libcamera { + +SwStatsCpu::SwStatsCpu() + : SwStats() +{ + sharedStats_ = SharedMemObject("softIsp_stats"); + if (!sharedStats_.fd().isValid()) + LOG(SwStats, Error) + << "Failed to create shared memory for statistics"; +} + +/* for brightness values in the 0 to 255 range: */ +static const unsigned int BRIGHT_LVL = 170U << 8; +static const unsigned int TOO_BRIGHT_LVL = 210U << 8; + +static const unsigned int RED_Y_MUL = 77; /* 0.30 * 256 */ +static const unsigned int GREEN_Y_MUL = 150; /* 0.59 * 256 */ +static const unsigned int BLUE_Y_MUL = 29; /* 0.11 * 256 */ + +static inline __attribute__((always_inline)) void +statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bggr, unsigned int &bright_sum_, unsigned int &too_bright_sum_, SwIspStats &stats_) +{ + const int width_in_bytes = width * 5 / 4; + uint8_t r, g, b, g2; + unsigned int y_val; + unsigned int sumR = 0; + unsigned int sumG = 0; + unsigned int sumB = 0; + + unsigned int bright_sum = 0; + unsigned int too_bright_sum = 0; + + for (int x = 0; x < width_in_bytes; x += 5) { + if (bggr) { + /* BGGR */ + b = src0[x]; + g = src0[x + 1]; + g2 = src1[x]; + r = src1[x + 1]; + } else { + /* GBRG */ + g = src0[x]; + b = src0[x + 1]; + r = src1[x]; + g2 = src1[x + 1]; + } + g = g + g2 / 2; + + sumR += r; + sumG += g; + sumB += b; + + y_val = r * RED_Y_MUL; + y_val += g * GREEN_Y_MUL; + y_val += b * BLUE_Y_MUL; + if (y_val > BRIGHT_LVL) ++bright_sum; + if (y_val > TOO_BRIGHT_LVL) ++too_bright_sum; + } + + stats_.sumR_ += sumR; + stats_.sumG_ += sumG; + stats_.sumB_ += sumB; + + bright_sum_ += bright_sum; + too_bright_sum_ += too_bright_sum; +} + +void SwStatsCpu::statsBGGR10PLine0(const uint8_t *src, unsigned int stride) +{ + statsBayer10P(window_.width, src, src + stride, true, bright_sum_, too_bright_sum_, stats_); +} + +void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src, unsigned int stride) +{ + statsBayer10P(window_.width, src, src + stride, false, bright_sum_, too_bright_sum_, stats_); +} + +void SwStatsCpu::statsGRBG10PLine0(const uint8_t *src, unsigned int stride) +{ + /* GRBG is BGGR with the lines swapped */ + statsBayer10P(window_.width, src + stride, src, true, bright_sum_, too_bright_sum_, stats_); +} + +void SwStatsCpu::statsRGGB10PLine0(const uint8_t *src, unsigned int stride) +{ + /* RGGB is GBRG with the lines swapped */ + statsBayer10P(window_.width, src + stride, src, false, bright_sum_, too_bright_sum_, stats_); +} + +void SwStatsCpu::resetStats(void) +{ + stats_.sumR_ = 0; + stats_.sumB_ = 0; + stats_.sumG_ = 0; + + bright_sum_ = 0; + too_bright_sum_ = 0; +} + +void SwStatsCpu::finishStats(void) +{ + /* calculate the fractions of "bright" and "too bright" pixels */ + stats_.bright_ratio = (float)bright_sum_ / (window_.height * window_.width / 16); + stats_.too_bright_ratio = (float)too_bright_sum_ / (window_.height * window_.width / 16); + + *sharedStats_ = stats_; + statsReady.emit(0); +} + +int SwStatsCpu::configure(const StreamConfiguration &inputCfg) +{ + BayerFormat bayerFormat = + BayerFormat::fromPixelFormat(inputCfg.pixelFormat); + + startFrame_ = (SwStats::statsVoidFn)&SwStatsCpu::resetStats; + finishFrame_ = (SwStats::statsVoidFn)&SwStatsCpu::finishStats; + + if (bayerFormat.bitDepth == 10 && + bayerFormat.packing == BayerFormat::Packing::CSI2) { + bpp_ = 10; + patternSize_.height = 2; + patternSize_.width = 4; /* 5 bytes per *4* pixels */ + y_skip_mask_ = 0x0c; /* Skip every 3th and 4th line */ + x_shift_ = 0; + + switch (bayerFormat.order) { + case BayerFormat::BGGR: + stats0_ = (SwStats::statsProcessFn)&SwStatsCpu::statsBGGR10PLine0; + return 0; + case BayerFormat::GBRG: + stats0_ = (SwStats::statsProcessFn)&SwStatsCpu::statsGBRG10PLine0; + return 0; + case BayerFormat::GRBG: + stats0_ = (SwStats::statsProcessFn)&SwStatsCpu::statsGRBG10PLine0; + return 0; + case BayerFormat::RGGB: + stats0_ = (SwStats::statsProcessFn)&SwStatsCpu::statsRGGB10PLine0; + return 0; + default: + break; + } + /* } else if (future supported fmts) { ... */ + } + + LOG(SwStats, Info) + << "Unsupported input format " << inputCfg.pixelFormat.toString(); + return -EINVAL; +} + +} /* namespace libcamera */ From patchwork Thu Dec 14 12:13:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19322 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 1777ABD87C for ; Thu, 14 Dec 2023 12:14:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C59FB62B60; Thu, 14 Dec 2023 13:14:10 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556050; bh=LhipIp4GtupJ6IaZ4rU1hdfOM4k+B4tp1rNOs3vZZhM=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=X+PK7G6ejJzjWapZ9vXWaVYpXWCPpwdoIkkipHzSzcbBHyzBRzL6VStJYixi1g4Ra AtsYkSS/A+ZKxhCBlp3UNKIPxgbIJVXFy5BFfQsbElzVu8nC2KCmXYlmMTwuJGYtSc aOVtShLA944qyHzSlTRJ6WgaMtpPw3wiQqq8BGS5XXikl8ep2ZAqsy2FNw+dQkL9go Io9gYhfUG1bsy/hwD0FMBLDHsM+Gxjx45hyrD6UH8bwZihCI8lQ0JmYFAVf3X2LH4M KM72jvlG+B6t7QVJlVWsT4vpjCwLhAr+/y2yp1/9iCJsrFJlVRyYmfHl/NNR5aWHa0 KoJ8p2D3yixkQ== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9495862B5C for ; Thu, 14 Dec 2023 13:14:07 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="MiqDOFlK"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556046; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tdIzGLQxhxYICZ6OdjRLAGlPb0lmvJYHuBZDXsIFGfs=; b=MiqDOFlK8hYw42doQy/SeEYGJFTb8cytEFspUufA5en9Het49HNR5O6izPOJcPnzKVkHPe Mm1DEpfAy/BrwweIeKCyNymzx5muhHGV9je6FZRaLBN0vAOQ3MshlU/Kn3PsPheUzKCYXh lE+dQSaRNRJcJ463Q3oS9UcNZPpyO4Q= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-625-TclWStvuNSSePfAJU6mq_g-1; Thu, 14 Dec 2023 07:14:00 -0500 X-MC-Unique: TclWStvuNSSePfAJU6mq_g-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id D530185A588; Thu, 14 Dec 2023 12:13:59 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8ED601121306; Thu, 14 Dec 2023 12:13:58 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:43 +0100 Message-ID: <20231214121350.206015-6-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 05/11] libcamera: software_isp: Add Debayer base class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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. Co-authored-by: Andrey Konovalov Signed-off-by: Andrey Konovalov Signed-off-by: Hans de Goede --- .../libcamera/internal/software_isp/debayer.h | 90 +++++++++++++++++++ .../internal/software_isp/debayer_params.h | 24 +++++ .../internal/software_isp/meson.build | 2 + src/libcamera/software_isp/debayer.cpp | 22 +++++ src/libcamera/software_isp/meson.build | 1 + 5 files changed, 139 insertions(+) create mode 100644 include/libcamera/internal/software_isp/debayer.h create mode 100644 include/libcamera/internal/software_isp/debayer_params.h create mode 100644 src/libcamera/software_isp/debayer.cpp diff --git a/include/libcamera/internal/software_isp/debayer.h b/include/libcamera/internal/software_isp/debayer.h new file mode 100644 index 00000000..206bc2ac --- /dev/null +++ b/include/libcamera/internal/software_isp/debayer.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * debayer.h - debayering base class + */ + +#pragma once + +#include + +#include +#include + +#include +#include + +#include "libcamera/internal/software_isp/debayer_params.h" + +namespace libcamera { + +class FrameBuffer; + +LOG_DECLARE_CATEGORY(Debayer) + +class Debayer +{ +public: + virtual ~Debayer() = 0; + + /* + * Setup the Debayer object according to the passed in parameters. + * Return 0 on success, a negative errno value on failure + * (unsupported parameters). + */ + virtual int configure(const StreamConfiguration &inputCfg, + const std::vector> &outputCfgs) = 0; + + /* + * Get width and height at which the bayer-pattern repeats. + * Return pattern-size or an empty Size for an unsupported inputFormat. + */ + virtual Size patternSize(PixelFormat inputFormat) = 0; + + virtual std::vector formats(PixelFormat inputFormat) = 0; + virtual std::tuple + strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) = 0; + + /* + * Note DebayerParams is passed by value deliberately so that a copy is passed + * when this is run in another thread to invokeMethod. + */ + virtual void process(FrameBuffer *input, FrameBuffer *output, DebayerParams params) = 0; + + /* sizes() - Get supported output sizes for given input fmt + size */ + SizeRange sizes(PixelFormat inputFormat, const Size &inputSize) + { + Size pattern_size = patternSize(inputFormat); + + if (pattern_size.isNull()) + return {}; + + /* + * For debayer interpolation a border of pattern-height x pattern-width + * is kept around the entire image. Combined with a minimum-size of + * pattern-height x pattern-width this means the input-size needs to be + * at least (3 * pattern-height) x (3 * pattern-width). + */ + if (inputSize.width < (3 * pattern_size.width) || + inputSize.height < (3 * 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 * pattern_size.height) & ~(pattern_size.height - 1)), + pattern_size.width, pattern_size.height); + } + + Signal inputBufferReady; + Signal outputBufferReady; +}; + +} /* namespace libcamera */ 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..885d3605 --- /dev/null +++ b/include/libcamera/internal/software_isp/debayer_params.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * swstats.h - software statistics base class + */ + +#pragma once + +namespace libcamera { + +struct DebayerParams { + /* Red Gain, 128 = 0.5, 256 = 1.0, 512 = 2.0, etc. */ + unsigned int gainR; + /* Blue Gain, same range as Red Gain. */ + unsigned int gainB; + /* 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 1d9e4018..7e40925e 100644 --- a/include/libcamera/internal/software_isp/meson.build +++ b/include/libcamera/internal/software_isp/meson.build @@ -1,6 +1,8 @@ # SPDX-License-Identifier: CC0-1.0 libcamera_internal_headers += files([ + 'debayer.h', + 'debayer_params.h', 'swisp_stats.h', 'swstats.h', 'swstats_cpu.h', diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp new file mode 100644 index 00000000..442da1ac --- /dev/null +++ b/src/libcamera/software_isp/debayer.cpp @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * debayer.cpp - debayer base class + */ + +#include "libcamera/internal/software_isp/debayer.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(Debayer) + +Debayer::~Debayer() +{ +} + +} /* namespace libcamera */ diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build index d31c6217..d4ae5ac7 100644 --- a/src/libcamera/software_isp/meson.build +++ b/src/libcamera/software_isp/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: CC0-1.0 libcamera_sources += files([ + 'debayer.cpp', 'swstats.cpp', 'swstats_cpu.cpp', ]) From patchwork Thu Dec 14 12:13:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19321 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id BF750C32BC for ; Thu, 14 Dec 2023 12:14:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EC26462B5D; Thu, 14 Dec 2023 13:14:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556047; bh=GfZfkk0Oytpvo6soPIgd21f0jB/sJAsL1kvfFHeCoHc=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=i/guXG2fiMAOszFp5bhGoKvQC/ko5kGIhgcMw2/NRwU6Z9h0Tw+xb1o2KrR+TDRiP NU1dRkYZeI89bCqhcsR9UofijBZe79esu4RA25Q6RyS38Np650vMm8VAy/8R2Tf5bV eGNsN3IdWqG9HDLTZL14JINm+RGVfitV2vS8dZkGkhU3maeRP3LiX76rUe1E5BEWgq OdM+7fj04fiCgB1G8LYit6wZ18ZSjlqfIXI17srdijxaDLawwpz5gpo355PxybzD6k r8Hf9QWx0wAGwcvw/13sVcvHnBdkHhNeV93gVBNNtRGF5xn9q0PAzWaNZ7U//kdAEi 1IU8L4YUDOB/Q== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5E4F562B30 for ; Thu, 14 Dec 2023 13:14:06 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="cPLViyPA"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556045; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mFVu3NrnaaUBgLHOHTuSqPnfWwlkpIlqdImBfDx2f3U=; b=cPLViyPARk6v4NplOyvze1/an2kH7cs+0VguSypvygvP3Q1hrdNJpEsSfbmRZEZmFwhOaF taEKnWn07ANJKwpJVbNf3NiSkhfURBOQiEw4BRSEpGjxcr7mK/saULGeS/9RVq+1i/zvKQ mCzD6xAKpG1FYfNPTCkfuN9Zmo0EH6M= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-682-0HL2kF7ANCyBU-_ChQ33gQ-1; Thu, 14 Dec 2023 07:14:02 -0500 X-MC-Unique: 0HL2kF7ANCyBU-_ChQ33gQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8A444380673D; Thu, 14 Dec 2023 12:14:01 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id 128281121306; Thu, 14 Dec 2023 12:13:59 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:44 +0100 Message-ID: <20231214121350.206015-7-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 06/11] libcamera: software_isp: Add DebayerCpu class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Pavel Machek , Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add CPU based debayering implementation. This initial implementation only supports debayering packed 10 bits per pixel bayer data in the 4 standard bayer orders. Co-authored-by: Andrey Konovalov Signed-off-by: Andrey Konovalov Suggested-by: Pavel Machek Signed-off-by: Pavel Machek Signed-off-by: Hans de Goede --- .../internal/software_isp/debayer_cpu.h | 104 +++++ .../internal/software_isp/meson.build | 1 + src/libcamera/software_isp/debayer_cpu.cpp | 440 ++++++++++++++++++ src/libcamera/software_isp/meson.build | 1 + 4 files changed, 546 insertions(+) create mode 100644 include/libcamera/internal/software_isp/debayer_cpu.h create mode 100644 src/libcamera/software_isp/debayer_cpu.cpp diff --git a/include/libcamera/internal/software_isp/debayer_cpu.h b/include/libcamera/internal/software_isp/debayer_cpu.h new file mode 100644 index 00000000..7fb5be77 --- /dev/null +++ b/include/libcamera/internal/software_isp/debayer_cpu.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 + * + * debayer_cpu.h - CPU based debayering header + */ + +#pragma once + +#include +#include +#include + +#include + +#include "libcamera/internal/software_isp/swstats_cpu.h" +#include "libcamera/internal/software_isp/debayer.h" + +namespace libcamera { + +class DebayerCpu : public Debayer, public Object +{ +public: + /* + * FIXME this should be a plain (implementation independent) SwStats + * this can be fixed once getStats() is dropped. + */ + DebayerCpu(std::unique_ptr stats); + ~DebayerCpu() {} + + /* + * Setup the Debayer object according to the passed in parameters. + * Return 0 on success, a negative errno value on failure + * (unsupported parameters). + */ + int configure(const StreamConfiguration &inputCfg, + const std::vector> &outputCfgs); + + /* + * Get width and height at which the bayer-pattern repeats. + * Return pattern-size or an empty Size for an unsupported inputFormat. + */ + Size patternSize(PixelFormat inputFormat); + + std::vector formats(PixelFormat input); + std::tuple + strideAndFrameSize(const PixelFormat &outputFormat, const Size &size); + + void process(FrameBuffer *input, FrameBuffer *output, DebayerParams params); + + const SharedFD &getStatsFD() { return stats_->getStatsFD(); } + + unsigned int frameSize() { return outputConfig_.frameSize; } + + /* FIXME this should be dropped once AWB has moved to the IPA */ + SwIspStats getStats() { return stats_->getStats(); } +private: + void process2(const uint8_t *src, uint8_t *dst); + void process4(const uint8_t *src, uint8_t *dst); + /* 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); + + typedef void (DebayerCpu::*debayerFn)(uint8_t *dst, const uint8_t *src); + + struct DebayerInputConfig { + Size patternSize; + unsigned int bpp; /* Memory used per pixel, not precision */ + unsigned int x_shift; /* Offset of 0/1 applied to window_.x */ + unsigned int stride; + std::vector 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); + + debayerFn debayer0_; + debayerFn debayer1_; + debayerFn debayer2_; + debayerFn debayer3_; + uint8_t red_[256]; + uint8_t green_[256]; + uint8_t blue_[256]; + Rectangle window_; + DebayerInputConfig inputConfig_; + DebayerOutputConfig outputConfig_; + std::unique_ptr stats_; + float gamma_correction_; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build index 7e40925e..b5a0d737 100644 --- a/include/libcamera/internal/software_isp/meson.build +++ b/include/libcamera/internal/software_isp/meson.build @@ -2,6 +2,7 @@ libcamera_internal_headers += files([ 'debayer.h', + 'debayer_cpu.h', 'debayer_params.h', 'swisp_stats.h', 'swstats.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..3eacdd5d --- /dev/null +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -0,0 +1,440 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * Copyright (C) 2023, Red Hat Inc. + * + * Authors: + * Hans de Goede + * + * debayer_cpu.cpp - CPU based debayering class + */ + +#include "libcamera/internal/software_isp/debayer_cpu.h" + +#include + +#include + +#include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/mapped_framebuffer.h" + +namespace libcamera { + +DebayerCpu::DebayerCpu(std::unique_ptr stats) + : stats_(std::move(stats)), gamma_correction_(1.0) +{ + /* Gamma curve is stored in green lookup, initialize to 1.0 curve */ + for (int i = 0; i < 256; i++) + green_[i] = i; +} + +struct ctxt_8bit_src { + /* Pointers to previous, current and next lines */ + const uint8_t *prev; + const uint8_t *curr; + const uint8_t *next; + + /* Pointers to gamma correction tables */ + const uint8_t *red; + const uint8_t *green; + const uint8_t *blue; +}; + +static inline void bggr8_bgr888(const struct ctxt_8bit_src &c, uint8_t *&dst, int x, int p, int n) +{ + *dst++ = c.blue[c.curr[x]]; + *dst++ = c.green[(c.prev[x] + c.curr[x - p] + c.curr[x + n] + c.next[x]) / 4]; + *dst++ = c.red[(c.prev[x - p] + c.prev[x + n] + c.next[x - p] + c.next[x + n]) / 4]; +} + +static inline void grbg8_bgr888(const struct ctxt_8bit_src &c, uint8_t *&dst, int x, int p, int n) +{ + *dst++ = c.blue[(c.prev[x] + c.next[x]) / 2]; + *dst++ = c.green[c.curr[x]]; + *dst++ = c.red[(c.curr[x - p] + c.curr[x + n]) / 2]; +} + +static inline void gbrg8_bgr888(const struct ctxt_8bit_src &c, uint8_t *&dst, int x, int p, int n) +{ + *dst++ = c.blue[(c.curr[x - p] + c.curr[x + n]) / 2]; + *dst++ = c.green[c.curr[x]]; + *dst++ = c.red[(c.prev[x] + c.next[x]) / 2]; +} + +static inline void rggb8_bgr888(const struct ctxt_8bit_src &c, uint8_t *&dst, int x, int p, int n) +{ + *dst++ = c.blue[(c.prev[x - p] + c.prev[x + n] + c.next[x - p] + c.next[x + n]) / 4]; + *dst++ = c.green[(c.prev[x] + c.curr[x - p] + c.curr[x + n] + c.next[x]) / 4]; + *dst++ = c.red[c.curr[x]]; +} + +void DebayerCpu::debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src) +{ + const int width_in_bytes = window_.width * 5 / 4; + struct ctxt_8bit_src c = { + src - inputConfig_.stride, src, src + inputConfig_.stride, + red_, green_, blue_ }; + + /* + * 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. + * x++ in the for-loop skips the 5th byte with 4 x 2 lsb-s for 10bit packed. + */ + for (int x = 0; x < width_in_bytes; x++) { + /* Even pixel */ + bggr8_bgr888(c, dst, x++, 2, 1); + /* Odd pixel BGGR -> GBRG */ + gbrg8_bgr888(c, dst, x++, 1, 1); + /* Same thing for next 2 pixels */ + bggr8_bgr888(c, dst, x++, 1, 1); + gbrg8_bgr888(c, dst, x++, 1, 2); + } +} + +void DebayerCpu::debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src) +{ + const int width_in_bytes = window_.width * 5 / 4; + struct ctxt_8bit_src c = { + src - inputConfig_.stride, src, src + inputConfig_.stride, + red_, green_, blue_ }; + + for (int x = 0; x < width_in_bytes; x++) { + /* Even pixel */ + grbg8_bgr888(c, dst, x++, 2, 1); + /* Odd pixel GRBG -> RGGB */ + rggb8_bgr888(c, dst, x++, 1, 1); + /* Same thing for next 2 pixels */ + grbg8_bgr888(c, dst, x++, 1, 1); + rggb8_bgr888(c, dst, x++, 1, 2); + } +} + +void DebayerCpu::debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src) +{ + const int width_in_bytes = window_.width * 5 / 4; + struct ctxt_8bit_src c = { + src - inputConfig_.stride, src, src + inputConfig_.stride, + red_, green_, blue_ }; + + for (int x = 0; x < width_in_bytes; x++) { + /* Even pixel */ + gbrg8_bgr888(c, dst, x++, 2, 1); + /* Odd pixel GBGR -> BGGR */ + bggr8_bgr888(c, dst, x++, 1, 1); + /* Same thing for next 2 pixels */ + gbrg8_bgr888(c, dst, x++, 1, 1); + bggr8_bgr888(c, dst, x++, 1, 2); + } +} + +void DebayerCpu::debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src) +{ + const int width_in_bytes = window_.width * 5 / 4; + struct ctxt_8bit_src c = { + src - inputConfig_.stride, src, src + inputConfig_.stride, + red_, green_, blue_ }; + + for (int x = 0; x < width_in_bytes; x++) { + /* Even pixel */ + rggb8_bgr888(c, dst, x++, 2, 1); + /* Odd pixel RGGB -> GRBG*/ + grbg8_bgr888(c, dst, x++, 1, 1); + /* Same thing for next 2 pixels */ + rggb8_bgr888(c, dst, x++, 1, 1); + grbg8_bgr888(c, dst, x++, 1, 2); + } +} + +int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config) +{ + BayerFormat bayerFormat = + BayerFormat::fromPixelFormat(inputFormat); + + if (bayerFormat.bitDepth == 10 && + bayerFormat.packing == BayerFormat::Packing::CSI2) { + config.bpp = 10; + config.patternSize.height = 2; + config.patternSize.width = 4; /* 5 bytes per *4* pixels */ + config.x_shift = 0; + config.outputFormats = std::vector({ formats::RGB888 }); + + switch (bayerFormat.order) { + case BayerFormat::BGGR: + case BayerFormat::GBRG: + case BayerFormat::GRBG: + case BayerFormat::RGGB: + return 0; + default: + break; + } + /* } else if (future supported fmts) { ... */ + } + + 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> &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; + + stats_->setWindow(window_); + + /* This *must* be done after the stats_->setWindow() call! */ + window_.x += inputConfig_.x_shift; + + return 0; +} + +Size DebayerCpu::patternSize(PixelFormat inputFormat) +{ + DebayerCpu::DebayerInputConfig config; + + if (getInputConfig(inputFormat, config) != 0) + return {}; + + return config.patternSize; +} + +std::vector DebayerCpu::formats(PixelFormat inputFormat) +{ + DebayerCpu::DebayerInputConfig config; + + if (getInputConfig(inputFormat, config) != 0) + return std::vector(); + + return config.outputFormats; +} + +std::tuple +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::process2(const uint8_t *src, uint8_t *dst) +{ + unsigned int y_end = window_.y + window_.height; + + /* Adjust src to top left corner of the window */ + src += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8; + + stats_->startFrame(); + + for (unsigned int y = window_.y; y < y_end; y+= 2) { + stats_->processLine0(y, src, inputConfig_.stride); + (this->*debayer0_)(dst, src); + src += inputConfig_.stride; + dst += outputConfig_.stride; + + (this->*debayer1_)(dst, src); + src += inputConfig_.stride; + dst += outputConfig_.stride; + } + + stats_->finishFrame(); +} + +void DebayerCpu::process4(const uint8_t *src, uint8_t *dst) +{ + unsigned int y_end = window_.y + window_.height; + + /* Adjust src to top left corner of the window */ + src += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8; + + stats_->startFrame(); + + for (unsigned int y = window_.y; y < y_end; y+= 4) { + stats_->processLine0(y, src, inputConfig_.stride); + (this->*debayer0_)(dst, src); + src += inputConfig_.stride; + dst += outputConfig_.stride; + + (this->*debayer1_)(dst, src); + src += inputConfig_.stride; + dst += outputConfig_.stride; + + stats_->processLine2(y, src, inputConfig_.stride); + (this->*debayer2_)(dst, src); + src += inputConfig_.stride; + dst += outputConfig_.stride; + + (this->*debayer3_)(dst, src); + src += inputConfig_.stride; + dst += outputConfig_.stride; + } + + stats_->finishFrame(); +} + +void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams params) +{ + /* + * HACK use stats from previous frame to calculate red and blue gains + * for simple AWB. + * This overrides the passed in gains since nothing is setting these yet. + * FIXME this needs to be moved to the IPA providing the params and + * our caller then passing these in. + */ + struct SwIspStats stats = stats_->getStats(); + + /* 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_; + /**** End of HACK / FIXME ****/ + + /* Apply DebayerParams */ + if (params.gamma != gamma_correction_) { + for (int i = 0; i < 256; i++) + green_[i] = 255 * powf(i / 255.0, params.gamma); + + gamma_correction_ = params.gamma; + } + + for (int i = 0; i < 256; i++) { + int idx; + + /* Use gamma curve stored in green lookup, apply gamma after gain! */ + idx = std::min({ i * params.gainR / 256U, 255U }); + red_[i] = green_[idx]; + + idx = std::min({ i * params.gainB / 256U, 255U }); + blue_[i] = green_[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; + } + + 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(); + + outputBufferReady.emit(output); + inputBufferReady.emit(input); +} + +} /* namespace libcamera */ diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build index d4ae5ac7..6d7a44d7 100644 --- a/src/libcamera/software_isp/meson.build +++ b/src/libcamera/software_isp/meson.build @@ -2,6 +2,7 @@ libcamera_sources += files([ 'debayer.cpp', + 'debayer_cpu.cpp', 'swstats.cpp', 'swstats_cpu.cpp', ]) From patchwork Thu Dec 14 12:13:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19320 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C6466C3292 for ; Thu, 14 Dec 2023 12:14:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 302BD62B54; Thu, 14 Dec 2023 13:14:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556047; bh=Ay3s0M6HwV3o+TGd2e9TbWFIv6IMJfwN8Yo1FmDwhrc=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=i3LnDCLbShyI1NYVtRhQZO0afgWddCNdQgL6B4OPvUC6jbc+CqBla2Fk9YCaQ4Ouz h7535qVYez4lwb07jwfPbwhEvIk7ifKdEaxJxbSi+ur9w2N3BrZNRmeeR/GsiuFeMq uy8+tUw/yNvun0GHEt8ffQBRFXstIXe4LNuALpdmvA/kwWbkl7hq5E6YEC/tZ8AS1B ZUj4s8zmq4WAlJz/IkVCWRZ0lZJTXY9G3UHztuDnOZffIgT1qMR/IpnZqUrpieyYGp ny2N2CyYz18S3RV3QdTlbqVUjpbbcKEdYQAR4I97MKQkYDNVdpEDtVOYDc2sBuAuUD 91J5JAygV/A/g== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D6B0662B30 for ; Thu, 14 Dec 2023 13:14:05 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="DqlEgsGP"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556044; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6Y0U7F+ZB5/Naom5DJvGoBaR9EWGu1cAcFIzHl/r3f0=; b=DqlEgsGPaaVBB8Q1JEklTpiRpY7AHiieKpR9vx34FgvGalRqmqtovpuY0r1CTkB8OFjhbH DZAJYReZgw0oNofD7d+q11+PWlJUUw8Rv4IVL1iFMnEGB1pJk+fHBGu3oWkOZyTVyH+2eV lC9hr6lDT7vssgJunr5rp3f1K9ivwjc= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-651-tOeBJRxNNCW_8GxD3RRmVA-1; Thu, 14 Dec 2023 07:14:03 -0500 X-MC-Unique: tOeBJRxNNCW_8GxD3RRmVA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 132071C0512F; Thu, 14 Dec 2023 12:14:03 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id BB57A1121306; Thu, 14 Dec 2023 12:14:01 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:45 +0100 Message-ID: <20231214121350.206015-8-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 07/11] libcamera: ipa: add Soft IPA common files X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Andrey Konovalov Define the Soft IPA main and event interfaces, add IPASoftBase class the Soft IPA implementation inherit from. Signed-off-by: Andrey Konovalov --- include/libcamera/ipa/meson.build | 1 + include/libcamera/ipa/soft.mojom | 27 ++++++++++++ src/ipa/simple/common/meson.build | 17 ++++++++ src/ipa/simple/common/soft_base.cpp | 66 +++++++++++++++++++++++++++++ src/ipa/simple/common/soft_base.h | 47 ++++++++++++++++++++ src/ipa/simple/meson.build | 3 ++ 6 files changed, 161 insertions(+) create mode 100644 include/libcamera/ipa/soft.mojom create mode 100644 src/ipa/simple/common/meson.build create mode 100644 src/ipa/simple/common/soft_base.cpp create mode 100644 src/ipa/simple/common/soft_base.h create mode 100644 src/ipa/simple/meson.build diff --git a/include/libcamera/ipa/meson.build b/include/libcamera/ipa/meson.build index f3b4881c..894e38a6 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/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..c3449188 --- /dev/null +++ b/include/libcamera/ipa/soft.mojom @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* + * \todo Document the interface and remove the related EXCLUDE_PATTERNS entry. + * \todo Add a way to tell SoftIPA the list of params SoftISP accepts? + */ + +module ipa.soft; + +import "include/libcamera/ipa/core.mojom"; + +interface IPASoftInterface { + init(libcamera.IPASettings settings, + libcamera.SharedFD fdStats, + 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); +}; diff --git a/src/ipa/simple/common/meson.build b/src/ipa/simple/common/meson.build new file mode 100644 index 00000000..023e617b --- /dev/null +++ b/src/ipa/simple/common/meson.build @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: CC0-1.0 + +soft_ipa_common_sources = files([ + 'soft_base.cpp', +]) + +soft_ipa_common_includes = [ + include_directories('..'), +] + +soft_ipa_common_deps = [ + libcamera_private, +] + +soft_ipa_common_lib = static_library('soft_ipa_common', soft_ipa_common_sources, + include_directories : soft_ipa_common_includes, + dependencies : soft_ipa_common_deps) diff --git a/src/ipa/simple/common/soft_base.cpp b/src/ipa/simple/common/soft_base.cpp new file mode 100644 index 00000000..7bd9b8de --- /dev/null +++ b/src/ipa/simple/common/soft_base.cpp @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * + * soft-base.cpp - Software IPA base class + */ + +#include "soft_base.h" + +#include + +#include +#include + +#include + +namespace libcamera { + +LOG_DEFINE_CATEGORY(IPASoft) + +namespace ipa::soft { + +IPASoftBase::IPASoftBase() +{ +} + +IPASoftBase::~IPASoftBase() +{ +} + +int IPASoftBase::init([[maybe_unused]] const IPASettings &settings, + const SharedFD &fdStats, + const ControlInfoMap &sensorInfoMap) +{ + fdStats_ = std::move(fdStats); + if (!fdStats_.isValid()) { + LOG(IPASoft, Error) << "Invalid Statistics handle"; + return -ENODEV; + } + + return platformInit(sensorInfoMap); +} + +int IPASoftBase::configure(const ControlInfoMap &sensorInfoMap) +{ + return platformConfigure(sensorInfoMap); +} + +int IPASoftBase::start() +{ + return platformStart(); +} + +void IPASoftBase::stop() +{ + return platformStop(); +} + +void IPASoftBase::processStats(const ControlList &sensorControls) +{ + return platformProcessStats(sensorControls); +} + +} /* namespace ipa::soft */ + +} /* namespace libcamera */ diff --git a/src/ipa/simple/common/soft_base.h b/src/ipa/simple/common/soft_base.h new file mode 100644 index 00000000..bff53713 --- /dev/null +++ b/src/ipa/simple/common/soft_base.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * + * soft-base.h - Software IPA base class + */ +#pragma once + +#include +#include + +#include + +namespace libcamera { + +namespace ipa::soft { + +class IPASoftBase : public ipa::soft::IPASoftInterface +{ +public: + IPASoftBase(); + ~IPASoftBase(); + + int init(const IPASettings &settings, + const SharedFD &fdStats, + const ControlInfoMap &sensorInfoMap) override; + int configure(const ControlInfoMap &sensorInfoMap) override; + + int start() override; + void stop() override; + + void processStats(const ControlList &sensorControls) override; + +protected: + SharedFD fdStats_; + +private: + virtual int platformInit(const ControlInfoMap &sensorInfoMap) = 0; + virtual int platformConfigure(const ControlInfoMap &sensorInfoMap) = 0; + virtual int platformStart() = 0; + virtual void platformStop() = 0; + virtual void platformProcessStats(const ControlList &sensorControls) = 0; +}; + +} /* namespace ipa::soft */ + +} /* namespace libcamera */ diff --git a/src/ipa/simple/meson.build b/src/ipa/simple/meson.build new file mode 100644 index 00000000..9688bbdb --- /dev/null +++ b/src/ipa/simple/meson.build @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: CC0-1.0 + +subdir('common') From patchwork Thu Dec 14 12:13:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19323 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id B2F0EC32BD for ; Thu, 14 Dec 2023 12:14:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6087B62B5F; Thu, 14 Dec 2023 13:14:11 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556051; bh=cIwGSZBqCcMUmmZYG3IdVhUd/YqG/nRQW8zhG3I+T/0=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=BAqlFqwxev+GunrHEqOJMBFyUAr1alUdRBhbyHzSoF1V0sPYBIa2Isf6WDlpDG++I eCbDPxVW2yy6UxhaPMoIkXE9PHq3GHSin35dnx96sG1EW9jMiJ0hWcnmOtVh+vVEjY eXdLaSdzPBUmvnYUEKEInvkQJy01Whvy4Hm4jXMsuqahyuFskzLXOV1ifpSoEIxd9F uryWLdlEG1yJhNmccTE0zOmoLa4hS5m2suI7uyC2m1FeUbtVawsJkvXjZ756vw1MnY 2hfe56kRrZ+XG5h9mhpVeSUKZGbz1LFt9WXuYAMM3MTjcNhOd98fL1nDiMxcnEOxmO JShqRCKKxYC2w== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B223362B3E for ; Thu, 14 Dec 2023 13:14:09 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="foubqEjN"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556048; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cf2qmq/dunTCI05CWmbCUZkFsIFiXs+iFv8ck+8fkuI=; b=foubqEjNJYT+pNsPgsm8/RF2B/lIxPwrzMSZJu7vSWneUhbTtVgpdVynErFbw0PJKOOFCr XrTaLPXtQFY0otgDfl4dsxgNHUO4h+W8hX39FspFcRwvjsB7rIi/EvsmmnRCx+zm1xaZWq GRVTouNoV2iwC0whmGqmMGBjF/D9GU8= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-623-RwPYhJi0NCiHur_fSx645A-1; Thu, 14 Dec 2023 07:14:05 -0500 X-MC-Unique: RwPYhJi0NCiHur_fSx645A-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8ACFA3869143; Thu, 14 Dec 2023 12:14:04 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id 465B71121306; Thu, 14 Dec 2023 12:14:03 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:46 +0100 Message-ID: <20231214121350.206015-9-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 08/11] libcamera: ipa: Soft IPA: add a Simple Soft IPA implementation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Andrey Konovalov Signed-off-by: Andrey Konovalov --- meson_options.txt | 3 +- src/ipa/simple/meson.build | 9 ++ src/ipa/simple/simple/data/meson.build | 9 ++ src/ipa/simple/simple/data/soft.conf | 3 + src/ipa/simple/simple/meson.build | 26 +++ src/ipa/simple/simple/soft_simple.cpp | 210 +++++++++++++++++++++++++ 6 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 src/ipa/simple/simple/data/meson.build create mode 100644 src/ipa/simple/simple/data/soft.conf create mode 100644 src/ipa/simple/simple/meson.build create mode 100644 src/ipa/simple/simple/soft_simple.cpp diff --git a/meson_options.txt b/meson_options.txt index 5fdc7be8..8ec08658 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/simple', 'vimc'], description : 'Select which IPA modules to build') option('lc-compliance', @@ -46,6 +46,7 @@ option('pipelines', 'rkisp1', 'rpi/vc4', 'simple', + 'simple/simple', 'uvcvideo', 'vimc' ], diff --git a/src/ipa/simple/meson.build b/src/ipa/simple/meson.build index 9688bbdb..14be5dc2 100644 --- a/src/ipa/simple/meson.build +++ b/src/ipa/simple/meson.build @@ -1,3 +1,12 @@ # SPDX-License-Identifier: CC0-1.0 subdir('common') + +foreach pipeline : pipelines + pipeline = pipeline.split('/') + if pipeline.length() < 2 or pipeline[0] != 'simple' + continue + endif + + subdir(pipeline[1]) +endforeach diff --git a/src/ipa/simple/simple/data/meson.build b/src/ipa/simple/simple/data/meson.build new file mode 100644 index 00000000..33548cc6 --- /dev/null +++ b/src/ipa/simple/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/simple/data/soft.conf b/src/ipa/simple/simple/data/soft.conf new file mode 100644 index 00000000..0c70e7c0 --- /dev/null +++ b/src/ipa/simple/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/simple/meson.build b/src/ipa/simple/simple/meson.build new file mode 100644 index 00000000..8b5d76b5 --- /dev/null +++ b/src/ipa/simple/simple/meson.build @@ -0,0 +1,26 @@ +# 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, + link_whole : soft_ipa_common_lib, + 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/simple/soft_simple.cpp b/src/ipa/simple/simple/soft_simple.cpp new file mode 100644 index 00000000..77be4f91 --- /dev/null +++ b/src/ipa/simple/simple/soft_simple.cpp @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * + * soft_simple.cpp - Simple Software Image Processing Algorithm module + */ + +#include + +#include +#include + +#include + +#include +#include + +#include "libcamera/internal/camera_sensor.h" +#include "libcamera/internal/software_isp/swisp_stats.h" + +#include "common/soft_base.h" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(IPASoft) + +namespace ipa::soft { + +class IPASoftSimple final : public IPASoftBase +{ +public: + IPASoftSimple() + : IPASoftBase(), ignore_updates_(0) + { + } + + ~IPASoftSimple() + { + if (stats_) + munmap(stats_, sizeof(SwIspStats)); + } + + int platformInit(const ControlInfoMap &sensorInfoMap) override; + int platformConfigure(const ControlInfoMap &sensorInfoMap) override; + int platformStart() override; + void platformStop() override; + void platformProcessStats(const ControlList &sensorControls) override; + +private: + void update_exposure(double ev_adjustment); + + SwIspStats *stats_; + int exposure_min_, exposure_max_; + int again_min_, again_max_; + int again_, exposure_; + int ignore_updates_; +}; + +int IPASoftSimple::platformInit(const ControlInfoMap &sensorInfoMap) +{ + stats_ = static_cast(mmap(nullptr, sizeof(SwIspStats), + PROT_READ | PROT_WRITE, MAP_SHARED, + fdStats_.get(), 0)); + if (!stats_) { + LOG(IPASoft, Error) << "Unable to map Statistics"; + return -ENODEV; + } + + 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::platformConfigure(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(); + if (!exposure_min_) { + LOG(IPASoft, Warning) << "Minimum exposure is zero, that can't be linear"; + exposure_min_ = 1; + } + exposure_max_ = exposure_info.max().get(); + again_min_ = gain_info.min().get(); + if (!again_min_) { + LOG(IPASoft, Warning) << "Minimum gain is zero, that can't be linear"; + again_min_ = 100; + } + again_max_ = gain_info.max().get(); + + LOG(IPASoft, Info) << "Exposure " << exposure_min_ << "-" << exposure_max_ + << ", gain " << again_min_ << "-" << again_max_; + + return 0; +} + +int IPASoftSimple::platformStart() +{ + return 0; +} + +void IPASoftSimple::platformStop() +{ +} + +void IPASoftSimple::platformProcessStats(const ControlList &sensorControls) +{ + double ev_adjustment = 0.0; + ControlList ctrls(sensorControls); + + /* + * Use 2 frames delay to make sure that the exposure and the gain set + * have applied to the camera sensor + */ + if (ignore_updates_ > 0) { + LOG(IPASoft, Debug) << "Skipping exposure update: " + << ignore_updates_; + --ignore_updates_; + return; + } + + if (stats_->bright_ratio < 0.01) + ev_adjustment = 1.1; + if (stats_->too_bright_ratio > 0.04) + ev_adjustment = 0.9; + + if (ev_adjustment != 0.0) { + /* sanity check */ + if (!sensorControls.contains(V4L2_CID_EXPOSURE) || + !sensorControls.contains(V4L2_CID_ANALOGUE_GAIN)) { + LOG(IPASoft, Error) << "Control(s) missing"; + return; + } + + exposure_ = ctrls.get(V4L2_CID_EXPOSURE).get(); + again_ = ctrls.get(V4L2_CID_ANALOGUE_GAIN).get(); + + update_exposure(ev_adjustment); + + ctrls.set(V4L2_CID_EXPOSURE, exposure_); + ctrls.set(V4L2_CID_ANALOGUE_GAIN, again_); + + ignore_updates_ = 2; + + setSensorControls.emit(ctrls); + } +} + +void IPASoftSimple::update_exposure(double ev_adjustment) +{ + double exp = (double)exposure_; + double gain = (double)again_; + double ev = ev_adjustment * exp * gain; + + /* + * Try to use the minimal possible analogue gain. + * The exposure can be any value from exposure_min_ to exposure_max_, + * and normally this should keep the frame rate intact. + */ + + exp = ev / again_min_; + if (exp > exposure_max_) + exposure_ = exposure_max_; + else if (exp < exposure_min_) + exposure_ = exposure_min_; + else + exposure_ = (int)exp; + + gain = ev / exposure_; + if (gain > again_max_) + again_ = again_max_; + else if (gain < again_min_) + again_ = again_min_; + else + again_ = (int)gain; + + LOG(IPASoft, Debug) << "Desired EV = " << ev + << ", real EV = " << (double)again_ * exposure_; +} + +} /* namespace ipa::soft */ + +/* + * External IPA module interface + */ +extern "C" { +const struct IPAModuleInfo ipaModuleInfo = { + IPA_MODULE_API_VERSION, + 0, + "SimplePipelineHandler", + "soft/simple", +}; + +IPAInterface *ipaCreate() +{ + return new ipa::soft::IPASoftSimple(); +} + +} /* extern "C" */ + +} /* namespace libcamera */ From patchwork Thu Dec 14 12:13:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19324 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 8F67BC3292 for ; Thu, 14 Dec 2023 12:14:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4611F62B61; Thu, 14 Dec 2023 13:14:12 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556052; bh=AzPbf99kmRo4L7Zn43l8oEDzEJoEC/Bv9o1ZyvIB0LY=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=3KobMLIQepuMLByMytZyjHMV6AF5ieDNdhtyIruya5OV3bRHw9tf4z1R0suUBWDHz /k2H8I5SyA0Wngpg5LL4mFdwXq6WFz8WaS5g1Zox+s3R0tez0dC9BUkP5/3dlA95/6 Ii5kFItYCjtcZkobD4kO4MowsVVNrmm7RepriQp9/MwWszTRuk1ekNx7pQsgLX4o/w HLS4z84aQzoMP2nynX+AJOvJrmMahudqOx+EnyjctgiKyl8RELPZqD30AbRdGR/wSG LS+2oEUjCNMhXNcKRnKNSVlefGJ4hirvOxVi3HYl2uQ5pWS27hsA4eXD9s5hdCJPXW 3GzBdh/VwG2xw== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C60AF62B61 for ; Thu, 14 Dec 2023 13:14:10 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="LoQiLexx"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556049; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=yDVEm3pYLfHh77GPI/fz95A+9YFc6sPF3hsMkf+AWCM=; b=LoQiLexx2KsQ9baRu8cVFT0wo5SC+SMECWXq0xKYMJ5t9XiVdIkACMXjsvj6XpB+dI1vu9 9UtdUa0eqE8hEIgFh2xOBK7uFPp6ApQ9FPcmonZ2wXMh5RAg7TZop/YokXOkl3egeqtZgJ OkcBdCa72wC9blTFZn43wFLXyZOOMQI= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-173-vGhwkzODNaWFO5mdrr15ZA-1; Thu, 14 Dec 2023 07:14:06 -0500 X-MC-Unique: vGhwkzODNaWFO5mdrr15ZA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0D7043C23FE8; Thu, 14 Dec 2023 12:14:06 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id BC30D1121306; Thu, 14 Dec 2023 12:14:04 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:47 +0100 Message-ID: <20231214121350.206015-10-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 09/11] libcamera: software_isp: add Simple SoftwareIsp implementation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Andrey Konovalov The implementation of SoftwareIsp handles creation of Soft IPA and interactions with it, so that the pipeline handler wouldn't need to care about the Soft IPA. Signed-off-by: Andrey Konovalov Co-authored-by: Hans de Goede Signed-off-by: Hans de Goede --- include/libcamera/internal/meson.build | 1 + .../internal/software_isp/meson.build | 1 + .../internal/software_isp/swisp_simple.h | 67 ++++++ src/libcamera/meson.build | 1 + src/libcamera/software_isp/meson.build | 19 ++ src/libcamera/software_isp/swisp_simple.cpp | 219 ++++++++++++++++++ 6 files changed, 308 insertions(+) create mode 100644 include/libcamera/internal/software_isp/swisp_simple.h create mode 100644 src/libcamera/software_isp/swisp_simple.cpp diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index b780777c..eeae801c 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 index b5a0d737..cf21ace5 100644 --- a/include/libcamera/internal/software_isp/meson.build +++ b/include/libcamera/internal/software_isp/meson.build @@ -4,6 +4,7 @@ libcamera_internal_headers += files([ 'debayer.h', 'debayer_cpu.h', 'debayer_params.h', + 'swisp_simple.h', 'swisp_stats.h', 'swstats.h', 'swstats_cpu.h', diff --git a/include/libcamera/internal/software_isp/swisp_simple.h b/include/libcamera/internal/software_isp/swisp_simple.h new file mode 100644 index 00000000..ee66e193 --- /dev/null +++ b/include/libcamera/internal/software_isp/swisp_simple.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * + * swisp_simple.h - Simple software ISP implementation + */ + +#pragma once + +#include +#include + +#include + +#include +#include + +#include "libcamera/internal/software_isp.h" +#include "libcamera/internal/software_isp/debayer_cpu.h" + +namespace libcamera { + +class SwIspSimple : public SoftwareIsp +{ +public: + SwIspSimple(PipelineHandler *pipe, const ControlInfoMap &sensorControls); + ~SwIspSimple() {} + + int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; } + bool isValid() const; + + std::vector formats(PixelFormat input); + SizeRange sizes(PixelFormat inputFormat, const Size &inputSize); + + std::tuple + strideAndFrameSize(const PixelFormat &outputFormat, const Size &size); + + int configure(const StreamConfiguration &inputCfg, + const std::vector> &outputCfgs); + int exportBuffers(unsigned int output, unsigned int count, + std::vector> *buffers); + void processStats(const ControlList &sensorControls); + + int start(); + void stop(); + + int queueBuffers(FrameBuffer *input, + const std::map &outputs); + + Signal &getSignalSetSensorControls(); + + void process(FrameBuffer *input, FrameBuffer *output); + +private: + void statsReady(int dummy); + void inputReady(FrameBuffer *input); + void outputReady(FrameBuffer *output); + + std::unique_ptr debayer_; + Thread ispWorkerThread_; + /* FIXME debayerParams should come from the IPA */ + DebayerParams debayerParams_; + + std::unique_ptr ipa_; +}; + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index b3606969..e758ac9c 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -70,6 +70,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 index 6d7a44d7..9464f2fd 100644 --- a/src/libcamera/software_isp/meson.build +++ b/src/libcamera/software_isp/meson.build @@ -6,3 +6,22 @@ libcamera_sources += files([ 'swstats.cpp', 'swstats_cpu.cpp', ]) + +# Software ISP is enabled for 'simple' pipeline handler. +# The 'pipelines' option value should be +# 'simple/' e.g.: +# -Dpipelines=simple/simple +# The source file should be named swisp_.cpp, +# e.g. 'swisp_simple.cpp'. + +foreach pipeline : pipelines + pipeline = pipeline.split('/') + if pipeline.length() == 2 and pipeline[0] == 'simple' + libcamera_sources += files([ + 'swisp_' + pipeline[1] + '.cpp', + ]) + # the 'break' below can be removed if/when multiple + # Software ISP implementations are allowed in single build + break + endif +endforeach diff --git a/src/libcamera/software_isp/swisp_simple.cpp b/src/libcamera/software_isp/swisp_simple.cpp new file mode 100644 index 00000000..ff05b6fe --- /dev/null +++ b/src/libcamera/software_isp/swisp_simple.cpp @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Linaro Ltd + * + * swisp_simple.cpp - Simple software ISP implementation + */ + +#include "libcamera/internal/software_isp/swisp_simple.h" + +#include +#include +#include + +#include +#include + +#include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/ipa_manager.h" +#include "libcamera/internal/mapped_framebuffer.h" + +namespace libcamera { + +SwIspSimple::SwIspSimple(PipelineHandler *pipe, const ControlInfoMap &sensorControls) + : SoftwareIsp(pipe, sensorControls), debayer_(nullptr), debayerParams_{256, 256, 0.5f} +{ + std::unique_ptr stats; + + stats = std::make_unique(); + if (!stats) { + LOG(SoftwareIsp, Error) << "Failed to create SwStatsCpu object"; + return; + } + + stats->statsReady.connect(this, &SwIspSimple::statsReady); + + debayer_ = std::make_unique(std::move(stats)); + if (!debayer_) { + LOG(SoftwareIsp, Error) << "Failed to create DebayerCpu object"; + return; + } + + debayer_->inputBufferReady.connect(this, &SwIspSimple::inputReady); + debayer_->outputBufferReady.connect(this, &SwIspSimple::outputReady); + + ipa_ = IPAManager::createIPA(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(), + sensorControls); + if (ret) { + LOG(SoftwareIsp, Error) << "IPA init failed"; + debayer_.reset(); + return; + } + + ipa_->configure(sensorControls); + + debayer_->moveToThread(&ispWorkerThread_); +} + +void SwIspSimple::processStats(const ControlList &sensorControls) +{ + ASSERT(ipa_); + ipa_->processStats(sensorControls); +} + +Signal &SwIspSimple::getSignalSetSensorControls() +{ + ASSERT(ipa_); + return ipa_->setSensorControls; +} + +bool SwIspSimple::isValid() const +{ + return !!debayer_; +} + +std::vector SwIspSimple::formats(PixelFormat inputFormat) +{ + ASSERT(debayer_ != nullptr); + + return debayer_->formats(inputFormat); +} + +SizeRange SwIspSimple::sizes(PixelFormat inputFormat, const Size &inputSize) +{ + ASSERT(debayer_ != nullptr); + + return debayer_->sizes(inputFormat, inputSize); +} + +std::tuple +SwIspSimple::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) +{ + ASSERT(debayer_ != nullptr); + + return debayer_->strideAndFrameSize(outputFormat, size); +} + +int SwIspSimple::configure(const StreamConfiguration &inputCfg, + const std::vector> &outputCfgs) +{ + ASSERT(debayer_ != nullptr); + + return debayer_->configure(inputCfg, outputCfgs); +} + +int SwIspSimple::exportBuffers(unsigned int output, unsigned int count, + std::vector> *buffers) +{ + ASSERT(debayer_ != nullptr); + + /* single output for now */ + if (output >= 1) + return -EINVAL; + + /* TODO: allocate from dma_heap; memfd buffs aren't allowed in FrameBuffer */ + for (unsigned int i = 0; i < count; i++) { + std::string name = "frame-" + std::to_string(i); + + const int ispFd = memfd_create(name.c_str(), 0); + int ret = ftruncate(ispFd, debayer_->frameSize()); + if (ret < 0) { + LOG(SoftwareIsp, Error) + << "ftruncate() for memfd failed " + << strerror(-ret); + return ret; + } + + FrameBuffer::Plane outPlane; + outPlane.fd = SharedFD(std::move(ispFd)); + outPlane.offset = 0; + outPlane.length = debayer_->frameSize(); + + std::vector planes{ outPlane }; + buffers->emplace_back(std::make_unique(std::move(planes))); + } + + return count; +} + +int SwIspSimple::queueBuffers(FrameBuffer *input, + const std::map &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; +} + +int SwIspSimple::start() +{ + int ret = ipa_->start(); + if (ret) + return ret; + + ispWorkerThread_.start(); + return 0; +} + +void SwIspSimple::stop() +{ + ispWorkerThread_.exit(); + ispWorkerThread_.wait(); + + ipa_->stop(); +} + +void SwIspSimple::process(FrameBuffer *input, FrameBuffer *output) +{ + debayer_->invokeMethod(&DebayerCpu::process, + ConnectionTypeQueued, input, output, debayerParams_); +} + +void SwIspSimple::statsReady(int dummy) +{ + ispStatsReady.emit(dummy); +} + +void SwIspSimple::inputReady(FrameBuffer *input) +{ + inputBufferReady.emit(input); +} + +void SwIspSimple::outputReady(FrameBuffer *output) +{ + outputBufferReady.emit(output); +} + +REGISTER_SOFTWAREISP(SwIspSimple) + +} /* namespace libcamera */ From patchwork Thu Dec 14 12:13:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19326 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id ABABEBD87C for ; Thu, 14 Dec 2023 12:14:17 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 60B2A62B5F; Thu, 14 Dec 2023 13:14:17 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556057; bh=l7oD6HIdD77CYGU9uuEocqLbyGC1rf8xx7342r8ozsM=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=XZnTP6NeshGUitGKMwg7Dt+O8jH7U0t4I7AyOEGGShKIYsXn/83vaAOZxbFOvEmG/ kQCw+cMA6/J20DENh3v1z6x2aZi/3hTj8Vik42xiebJL+Z06sfah08qzHt1A3I4GHJ oSlrDT3CcWZ4Sm5hU8YYsbwjAcHBTfdJirLBWRlvtYjBLIpthXSwvvVjQHDu5oUs75 7MNqVh19NMskqfjUh/86n2SH0G18IRhoi6SfKvLo/V/+YPas4Guh4b7N8D4nDuKfrq fsx0aVkxCMZGYZA43wSfx/i+oimZiNTB3RUhtTJfmW5i1wnoWPG1W1HGlTqA/C33R4 LfM0xyv/se7rA== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EEEFC62B5D for ; Thu, 14 Dec 2023 13:14:15 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="M99ztEoM"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556054; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qbyoho+qdUjOZkq+8rBesVoLNysW7/9t9VBb4248djw=; b=M99ztEoMEOpZ26xgA91UHTB0qBLc3TGzjqymfqxuAg3SRq5TykSrr628cLdZpbGy7g6MPo jkKo4jq2vrQT7W06XQNUvQTuO/zGHpekJ+QSHHD55mlJUnSbsvoBBmnLK2P+iDifQBi2W5 ojz1Qp7haqpCLV8N4tvOsdCwkyhwsIw= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-267-bF7tcZpMNT29YZBrCLEZFw-1; Thu, 14 Dec 2023 07:14:09 -0500 X-MC-Unique: bF7tcZpMNT29YZBrCLEZFw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 82AC7848C05; Thu, 14 Dec 2023 12:14:07 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3DDE41121306; Thu, 14 Dec 2023 12:14:06 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:48 +0100 Message-ID: <20231214121350.206015-11-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 10/11] libcamera: pipeline: simple: rename converterBuffers_ and related vars X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Andrey Konovalov 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. Signed-off-by: Andrey Konovalov --- 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 911051b2..878794f6 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -269,17 +269,18 @@ public: std::vector configs_; std::map> formats_; + std::vector> conversionBuffers_; + std::queue> conversionQueue_; + bool useConversion_; + std::unique_ptr converter_; - std::vector> converterBuffers_; - bool useConverter_; - std::queue> converterQueue_; private: void tryPipeline(unsigned int code, const Size &size); static std::vector 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 &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(); @@ -1156,14 +1157,14 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c) /* Configure the converter if needed. */ std::vector> 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); } @@ -1189,7 +1190,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 @@ -1210,13 +1211,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]; @@ -1235,7 +1236,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); @@ -1243,7 +1244,7 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL } /* Queue all internal buffers for capture. */ - for (std::unique_ptr &buffer : data->converterBuffers_) + for (std::unique_ptr &buffer : data->conversionBuffers_) video->queueBuffer(buffer.get()); } @@ -1255,7 +1256,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(); @@ -1263,7 +1264,7 @@ void SimplePipelineHandler::stopDevice(Camera *camera) video->bufferReady.disconnect(data, &SimpleCameraData::bufferReady); - data->converterBuffers_.clear(); + data->conversionBuffers_.clear(); releasePipeline(data); } @@ -1281,7 +1282,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); @@ -1290,8 +1291,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; } From patchwork Thu Dec 14 12:13:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 19325 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 44AEAC32BC for ; Thu, 14 Dec 2023 12:14:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D14DA62B5B; Thu, 14 Dec 2023 13:14:15 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1702556055; bh=SvP1FkKKNYMxeVmAP0diBuGTyhX0vgBAmfjbU0uJH7Y=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=TiCAMBjJFBFbC0rsocbrfdiJgSG4RiXKp9Cnw7hSWOatnHMEJI0caKx1XSX45rFnU Z63uRteDdAWQwe5L3HMeBiQFicQd7SJd1mQsGJiujqk6J7eRpPyO3QJ3hJuvwHxF6/ XqRKSP7JuBhU5DBQJaTO+c1MCiqW0EXglttDuvLO9vtzQmI9oSIP+dMgqLa0Xp8X1F xyUFoDfMCWFM0FV4UfUB8/I05WI05kCI7/DuBK1TNXRNpyDRFSeakKT7KDHxIotBvQ cZqx5xdSHGz0DW1sYkDybNYX0u0BjgCxakC8+nCoc8QkjftwJ0x1v+4CvqOv1hvcoI wexx0aNb1mvqA== Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9296862B5B for ; Thu, 14 Dec 2023 13:14:13 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Aw0lmtA/"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1702556052; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j1bYJhB2vRY4QSYQe1AJKp5Os8nPrf3VSOdxPv4ICZo=; b=Aw0lmtA/TAq+xXsvl6E9rIcTRBoq9H4n6CQOlOdZNHAepzkJNm97EEj6j9j6UzbHW90Po6 +4XDmIS+fPHjUaihx8YNFaRRNYB8mDffTqUYFo8vKi/GxQzLQwW9eoQaUmiJnzSC2C+vH+ NCdNWrDtKJBdnOC9IHQnfN1z9ZMCqV8= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-556-vI7mEXvfM2umZ-QBRAeseQ-1; Thu, 14 Dec 2023 07:14:09 -0500 X-MC-Unique: vI7mEXvfM2umZ-QBRAeseQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 03FE7185A780; Thu, 14 Dec 2023 12:14:09 +0000 (UTC) Received: from shalem.redhat.com (unknown [10.39.194.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id B304A1121306; Thu, 14 Dec 2023 12:14:07 +0000 (UTC) To: libcamera-devel@lists.libcamera.org, Andrey Konovalov Date: Thu, 14 Dec 2023 13:13:49 +0100 Message-ID: <20231214121350.206015-12-hdegoede@redhat.com> In-Reply-To: <20231214121350.206015-1-hdegoede@redhat.com> References: <20231214121350.206015-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [libcamera-devel] [PATCH 11/11] libcamera: pipeline: simple: enable use of Soft ISP and Soft IPA X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Hans de Goede via libcamera-devel From: Hans de Goede Reply-To: Hans de Goede Cc: Maxime Ripard , g.martti@gmail.com, t.langendam@gmail.com, srinivas.kandagatla@linaro.org, Bryan O'Donoghue , admin@dennisbonke.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Andrey Konovalov To enable the Simple Soft ISP and Soft IPA for simple pipeline handler configure the build with: -Dpipelines=simple/simple -Dipas=simple/simple If the pipeline uses Converter, Soft ISP and Soft IPA aren't available. Configuring the build with just: -Dpipelines=simple makes it to work like before - Soft ISP and Soft IPA aren't used. Signed-off-by: Andrey Konovalov --- src/libcamera/pipeline/simple/simple.cpp | 105 ++++++++++++++++++----- 1 file changed, 83 insertions(+), 22 deletions(-) diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 878794f6..249527a0 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.h" #include "libcamera/internal/v4l2_subdevice.h" #include "libcamera/internal/v4l2_videodevice.h" @@ -274,6 +275,7 @@ public: bool useConversion_; std::unique_ptr converter_; + std::unique_ptr swIsp_; private: void tryPipeline(unsigned int code, const Size &size); @@ -281,6 +283,9 @@ private: void conversionInputDone(FrameBuffer *buffer); void conversionOutputDone(FrameBuffer *buffer); + + void ispStatsReady(int dummy); + void setSensorControls(const ControlList &sensorControls); }; class SimpleCameraConfiguration : public CameraConfiguration @@ -509,6 +514,25 @@ int SimpleCameraData::init() } } + /* + * Create SoftwareIsp unconditionally if no converter is used + * - to be revisited + */ + if (!converter_) { + swIsp_ = SoftwareIspFactoryBase::create(pipe, sensor_->controls()); + if (!swIsp_) { + LOG(SimplePipeline, Warning) + << "Failed to create software ISP, disabling software debayering"; + swIsp_.reset(); + } else { + swIsp_->inputBufferReady.connect(this, &SimpleCameraData::conversionInputDone); + swIsp_->outputBufferReady.connect(this, &SimpleCameraData::conversionOutputDone); + swIsp_->ispStatsReady.connect(this, &SimpleCameraData::ispStatsReady); + + swIsp_->getSignalSetSensorControls().connect(this, &SimpleCameraData::setSensorControls); + } + } + video_ = pipe->video(entities_.back().entity); ASSERT(video_); @@ -599,12 +623,15 @@ void SimpleCameraData::tryPipeline(unsigned int code, const Size &size) config.captureFormat = pixelFormat; config.captureSize = format.size; - if (!converter_) { - config.outputFormats = { pixelFormat }; - config.outputSizes = config.captureSize; - } else { + 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); + } else { + config.outputFormats = { pixelFormat }; + config.outputSizes = config.captureSize; } configs_.push_back(config); @@ -750,9 +777,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 +825,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 +835,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 +865,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 SimpleCameraData::routedSourcePads(MediaPad *sink) { @@ -1013,8 +1056,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 { @@ -1177,7 +1222,8 @@ 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); } int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream, @@ -1191,8 +1237,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); } @@ -1237,10 +1285,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. */ @@ -1256,8 +1312,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();