From patchwork Thu Feb 4 10:05:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hirokazu Honda X-Patchwork-Id: 11140 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 A7A33BD162 for ; Thu, 4 Feb 2021 10:05:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 760AC61430; Thu, 4 Feb 2021 11:05:54 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="l0gOpmM0"; dkim-atps=neutral Received: from mail-pf1-x42a.google.com (mail-pf1-x42a.google.com [IPv6:2607:f8b0:4864:20::42a]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2560161402 for ; Thu, 4 Feb 2021 11:05:53 +0100 (CET) Received: by mail-pf1-x42a.google.com with SMTP id w14so1822556pfi.2 for ; Thu, 04 Feb 2021 02:05:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=9jWK4b9whbxiv8fx7ANqjpS0eyFsEYZHn6jOiX5aYYA=; b=l0gOpmM0PTpjmnAV2hH5RppMjhSOFh1lp/odhiGY9pewEl1BEkAhQsQPzmRNdMsIOd imiEWddiB+HhrnZCd4l4aJa5GNHRSDhTJbTGB4WlaG0FPWzwcx/iZL6cMxNYhIQlRNbx ZHkAQM4rsHV5/pwg0n4axKfthHASNU0hv442U= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=9jWK4b9whbxiv8fx7ANqjpS0eyFsEYZHn6jOiX5aYYA=; b=icT2QQIHRUyw8tvZnTG8xMEloPCi7KlkVibpN8Uw6pt9k36qLkiVPz70jSeu9YTi+S e8MAvDl+e4cq6CXKPuGm9aWtKZ6tktKbgvTDwdOw29SgyX+ica/7pYxpauHIviRE0NGX gcW3Gtpt93Qka783B9rWjbpfPLOsjJGlN9tZWIfErhekCuqV1Ga9U4HmX1oOKNR/YzFm nrZa/PFFm9RAhqEjcgZqEcJJ1unDxulyEyD8xaIN4D3x+7AY9TIny2K7PdJK1xUh6KHp 1ocZlXVBMsnHFpG6qjTMhQmIEVnmIKi1xcb8XlLcA6Vqf3HpEryI3dghvE+2ZneXulLi GPvw== X-Gm-Message-State: AOAM530IAaCHu6v5gq4UAb7r4isjLNvQLHk0KJDDpW1vhT3wiYcjatQ1 SMYL2K62WJD9xKkbouMfKQg+LZ4Z7rduoFlf X-Google-Smtp-Source: ABdhPJwu/DDS6qdbLn2wChigESHdwK95GkPJPUtryMsUu5/spgRkdFOcUTOeQUvnmYPKarPdqpsrNg== X-Received: by 2002:a63:3e0c:: with SMTP id l12mr8146527pga.165.1612433151477; Thu, 04 Feb 2021 02:05:51 -0800 (PST) Received: from hiroh.c.googlers.com.com (128.141.236.35.bc.googleusercontent.com. [35.236.141.128]) by smtp.gmail.com with ESMTPSA id j9sm5808418pgb.47.2021.02.04.02.05.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Feb 2021 02:05:50 -0800 (PST) From: Hirokazu Honda To: libcamera-devel@lists.libcamera.org Date: Thu, 4 Feb 2021 10:05:37 +0000 Message-Id: <20210204100541.657503-3-hiroh@chromium.org> X-Mailer: git-send-email 2.30.0.365.g02bc693789-goog In-Reply-To: <20210204100541.657503-1-hiroh@chromium.org> References: <20210204100541.657503-1-hiroh@chromium.org> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 2/6] libcamera: ipu3: Implement tryValidate() in IPU3CameraConfiguration 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: , Cc: hanlinchen@chromium.org Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" IPU3CameraConfiguration::tryValidate() is implemented. It is mostly the same as the validate() implementation. Signed-off-by: Hirokazu Honda --- src/libcamera/pipeline/ipu3/imgu.cpp | 2 +- src/libcamera/pipeline/ipu3/imgu.h | 2 +- src/libcamera/pipeline/ipu3/ipu3.cpp | 160 +++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 2 deletions(-) -- 2.30.0.365.g02bc693789-goog diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp index 5b1c0318..36c5c03c 100644 --- a/src/libcamera/pipeline/ipu3/imgu.cpp +++ b/src/libcamera/pipeline/ipu3/imgu.cpp @@ -377,7 +377,7 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) * \return An ImgUDevice::PipeConfig instance on success, an empty configuration * otherwise */ -ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe) +ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe) const { pipeConfigs.clear(); diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h index c73ac5a5..4204f50d 100644 --- a/src/libcamera/pipeline/ipu3/imgu.h +++ b/src/libcamera/pipeline/ipu3/imgu.h @@ -43,7 +43,7 @@ public: int init(MediaDevice *media, unsigned int index); - PipeConfig calculatePipeConfig(Pipe *pipe); + PipeConfig calculatePipeConfig(Pipe *pipe) const; int configure(const PipeConfig &pipeConfig, V4L2DeviceFormat *inputFormat); diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index db0d6b91..89f1983a 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -73,11 +73,15 @@ public: IPU3CameraConfiguration(IPU3CameraData *data); Status validate() override; + bool tryValidate(std::vector> &config) const override; const StreamConfiguration &cio2Format() const { return cio2Configuration_; } const ImgUDevice::PipeConfig imguConfig() const { return pipeConfig_; } private: + bool tryValidateInternal( + std::vector> &configs, + ImgUDevice::PipeConfig &pipeConfig) const; /* * The IPU3CameraData instance is guaranteed to be valid as long as the * corresponding Camera instance is valid. In order to borrow a @@ -140,6 +144,162 @@ IPU3CameraConfiguration::IPU3CameraConfiguration(IPU3CameraData *data) data_ = data; } + +bool IPU3CameraConfiguration::tryValidateInternal( + std::vector> &configs, + ImgUDevice::PipeConfig &pipeConfig) const +{ + if (configs.empty() || configs.size() > IPU3_MAX_STREAMS) + return false; + + unsigned int rawCount = 0; + unsigned int yuvCount = 0; + Size maxYuvSize; + for (size_t i = 0; i < configs.size(); ++i) { + const auto &cfg = configs[i].first; + const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat); + if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) { + rawCount++; + } else { + yuvCount++; + maxYuvSize.expandTo(cfg.size); + } + } + LOG(IPU3, Debug) << rawCount << ", " << yuvCount; + if (rawCount > 1 || yuvCount > 2) + return false; + + StreamConfiguration cio2Configuration = + data_->cio2_.generateConfiguration({}); + if (!cio2Configuration.pixelFormat.isValid()) + return false; + LOG(IPU3, Debug) << "CIO2 configuration: " << cio2Configuration.toString(); + + ImgUDevice::Pipe pipe{}; + pipe.input = cio2Configuration.size; + + bool mainOutputAvailable = true; + for (auto &[cfg, status] : configs) { + const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat); + const StreamConfiguration originalCfg = cfg; + + LOG(IPU3, Debug) << "Validating " << cfg.toString() + << " to the raw stream"; + if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) { + cfg.size = cio2Configuration.size; + cfg.pixelFormat = cio2Configuration.pixelFormat; + cfg.bufferCount = cio2Configuration.bufferCount; + cfg.stride = info.stride(cfg.size.width, 0, 64); + cfg.frameSize = info.frameSize(cfg.size, 64); + cfg.setStream(const_cast(&data_->rawStream_)); + LOG(IPU3, Debug) << "Assigned " << cfg.toString() + << " to the raw stream"; + } else { + unsigned int limit; + limit = utils::alignDown(cio2Configuration.size.width - 1, + IMGU_OUTPUT_WIDTH_MARGIN); + cfg.size.width = std::clamp(cfg.size.width, + IMGU_OUTPUT_MIN_SIZE.width, + limit); + + limit = utils::alignDown(cio2Configuration.size.height - 1, + IMGU_OUTPUT_HEIGHT_MARGIN); + cfg.size.height = std::clamp(cfg.size.height, + IMGU_OUTPUT_MIN_SIZE.height, + limit); + + cfg.size.alignDownTo(IMGU_OUTPUT_WIDTH_ALIGN, + IMGU_OUTPUT_HEIGHT_ALIGN); + + cfg.pixelFormat = formats::NV12; + cfg.bufferCount = IPU3_BUFFER_COUNT; + cfg.stride = info.stride(cfg.size.width, 0, 1); + cfg.frameSize = info.frameSize(cfg.size, 1); + + if (mainOutputAvailable && + (originalCfg.size == maxYuvSize || yuvCount == 1)) { + cfg.setStream(const_cast(&data_->outStream_)); + mainOutputAvailable = false; + + pipe.main = cfg.size; + if (yuvCount == 1) + pipe.viewfinder = pipe.main; + + LOG(IPU3, Debug) << "Assigned " << cfg.toString() + << " to the main output"; + } else { + cfg.setStream(const_cast(&data_->vfStream_)); + pipe.viewfinder = cfg.size; + + LOG(IPU3, Debug) << "Assigned " << cfg.toString() + << " to the viewfinder output"; + } + } + if (cfg.pixelFormat != originalCfg.pixelFormat || + cfg.size != originalCfg.size) { + LOG(IPU3, Debug) + << "Stream configuration adjusted to " + << cfg.toString(); + + status = Adjusted; + } + } + + if (yuvCount) { + pipeConfig = data_->imgu_->calculatePipeConfig(&pipe); + if (pipeConfig.isNull()) + return false; + } + return true; +} + +bool IPU3CameraConfiguration::tryValidate( + std::vector> &configs) const +{ + if (configs.empty()) + return Invalid; + + struct AcceptedConfig { + StreamConfiguration config; + Status status; + unsigned int index; + }; + std::vector acceptedConfigs; + for (unsigned int i = 0; i < configs.size(); ++i) { + LOG(IPU3, Debug) << "Trying config #" << i + << ": " << configs[i].first.toString(); + std::vector> + tryConfigs(acceptedConfigs.size() + 1); + for (unsigned int j = 0; j < acceptedConfigs.size(); ++j) { + tryConfigs[j].first = acceptedConfigs[j].config; + tryConfigs[j].second = Valid; + } + tryConfigs.back().first = configs[i].first; + tryConfigs.back().second = Valid; + ImgUDevice::PipeConfig tryPipeConfig; + if (!tryValidateInternal(tryConfigs, tryPipeConfig)) + continue; + + for (unsigned int j = 0; j < acceptedConfigs.size(); ++j) { + acceptedConfigs[j].config = tryConfigs[j].first; + acceptedConfigs[j].status = tryConfigs[j].second; + } + acceptedConfigs.push_back( + { tryConfigs[i].first, tryConfigs[i].second, i }); + } + + for (unsigned int i = 0; i < configs.size(); ++i) + configs[i].second = Invalid; + + for (auto &&ac : acceptedConfigs) { + unsigned int i = ac.index; + configs[i].first = std::move(ac.config); + configs[i].second = ac.status; + } + + return !acceptedConfigs.empty(); +} + CameraConfiguration::Status IPU3CameraConfiguration::validate() { Status status = Valid;