From patchwork Mon Jul 20 09:13:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 8870 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 93787BD792 for ; Mon, 20 Jul 2020 09:13:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6203B605C9; Mon, 20 Jul 2020 11:13:39 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="m4dxU722"; dkim-atps=neutral Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7EEBE605BB for ; Mon, 20 Jul 2020 11:13:35 +0200 (CEST) Received: by mail-wm1-x330.google.com with SMTP id c80so21520478wme.0 for ; Mon, 20 Jul 2020 02:13:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=xz6y/lKwinaj+jtgprrtx2kUePux8NUENK0+5gnGFGw=; b=m4dxU7225Xt5amA0nuZLMvradiY87iiTtMDfxEs+zpudAUM05DBUx6cJm4lPM9IClE 7O9w+422RV2kZ6fv5vC71JW6UXw/6tFhn7QUCaN/JxlrSgGYWjA27Wk5nHUIuSdSTQ6W mybSzdqqTa75uqQkACmhTstua34fePYPRPH00dRx4N3vEKr1dPRldxP+nyi7EmfxgyBN pz5v0wr5PnTAYZtkXaLDlZVMWYyQZafcE7yIDVkZ0P+rHXFrLzmUou0Agj/jG95AGPu3 PadZRjw5KHGMsUfBKE1UPfQlv+b+Bi0SMsTFO7uzwQHteCyccCdKdrAJBUoYz7d5A3yz oKGg== 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=xz6y/lKwinaj+jtgprrtx2kUePux8NUENK0+5gnGFGw=; b=lDcAIbmzXZwyF6f49US074wRfWQFxJo53vUuzxTvPrR9d+NdmJFIOwqh0hrbXzzVrf H+0aOlPtKKhbvcRRwMHwxbZXDjpRWXx5Cuq18lPHaR6UNQPo8epitdv0fWUf0ZYX71xU UVUFP3cTReaiRJnbLggxS986Y/Fy1akN3zbzudLT+ZCnN/kyihL+S+Lxg4jLpzw+NA7C s8PXCnzswtBcMagb3IDWkyhnch9JzG/VNxrEmcYMnVd0gK4G+DCiOGdnUWFMTQOER8ux UfsZA+QPUpe1damvqNd1xisaHMZout0f4j1W2n3IR1k01DHsx0Vj0HhC8XVl7iWI2QIO r6dg== X-Gm-Message-State: AOAM530js1G3Up+UpJSlKRcuBLeG2H1aRoOJQu/+hE6UFOR1R9B2G8ai twHEvHVI1RqfQreX5iHvDCNtyTxXsbG+iQ== X-Google-Smtp-Source: ABdhPJwsVwKrq77BlXk+pCoVfs6NXg5osAwBBkN7H3X3G3cfoF06FsMevKWerSgg0iZWU89W8PTbRw== X-Received: by 2002:a1c:1f54:: with SMTP id f81mr20484254wmf.4.1595236414662; Mon, 20 Jul 2020 02:13:34 -0700 (PDT) Received: from naushir-VirtualBox.patuck.local ([88.97.76.4]) by smtp.gmail.com with ESMTPSA id u1sm38137185wrb.78.2020.07.20.02.13.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 Jul 2020 02:13:34 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Mon, 20 Jul 2020 10:13:10 +0100 Message-Id: <20200720091311.805092-9-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200720091311.805092-1-naush@raspberrypi.com> References: <20200720091311.805092-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 8/9] libcamera: pipeline: raspberrypi: Add more robust stream buffer logic 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add further queueing into the RPiStream object to ensure that we always follow the buffer ordering (be it internal or external) given by incoming Requests. This is essential, otherwise we risk dropping frames that are meant to be part of a Request, and can cause the pipeline to stall indefinitely. This also prevents any possibility of mismatched frame buffers going through the pipeline and out to the application. Signed-off-by: Naushir Patuck Reviewed-by: Niklas Söderlund --- .../pipeline/raspberrypi/rpi_stream.cpp | 70 ++++++++++++++++--- .../pipeline/raspberrypi/rpi_stream.h | 12 +++- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp index 02f8d3e0..6635a751 100644 --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp @@ -112,25 +112,34 @@ int RPiStream::queueBuffer(FrameBuffer *buffer) */ if (!buffer) { if (availableBuffers_.empty()) { - LOG(RPISTREAM, Warning) << "No buffers available for " + LOG(RPISTREAM, Info) << "No buffers available for " << name_; - return -EINVAL; + /* + * Note that we need to requeue an internal buffer as soon + * as one becomes available. + */ + requeueBuffers_.push(nullptr); + return 0; } buffer = availableBuffers_.front(); availableBuffers_.pop(); } - LOG(RPISTREAM, Debug) << "Queuing buffer " << buffer->cookie() - << " for " << name_; + /* + * If no earlier requests are pending to be queued we can go ahead and + * queue the buffer into the device. + */ + if (requeueBuffers_.empty()) + return queueToDevice(buffer); - int ret = dev_->queueBuffer(buffer); - if (ret) { - LOG(RPISTREAM, Error) << "Failed to queue buffer for " - << name_; - } + /* + * There are earlier buffers to be queued, so this bufferm ust go on + * the waiting list. + */ + requeueBuffers_.push(buffer); - return ret; + return 0; } void RPiStream::returnBuffer(FrameBuffer *buffer) @@ -138,7 +147,35 @@ void RPiStream::returnBuffer(FrameBuffer *buffer) /* This can only be called for external streams. */ assert(external_); + /* Push this buffer back into the queue to be used again. */ availableBuffers_.push(buffer); + + /* + * Do we have any buffers that are waiting to be queued? + * If so, do it now as availableBuffers_ will not be empty. + */ + while (!requeueBuffers_.empty()) { + FrameBuffer *buffer = requeueBuffers_.front(); + + if (!buffer) { + /* + * We want to queue an internal buffer, but none + * are available. Can't do anything, quit the loop. + */ + if (availableBuffers_.empty()) + break; + + /* + * We want to queue an internal buffer, and at least one + * is available. + */ + buffer = availableBuffers_.front(); + availableBuffers_.pop(); + } + + requeueBuffers_.pop(); + queueToDevice(buffer); + } } bool RPiStream::findFrameBuffer(FrameBuffer *buffer) const @@ -155,10 +192,23 @@ bool RPiStream::findFrameBuffer(FrameBuffer *buffer) const void RPiStream::clearBuffers() { availableBuffers_ = std::queue{}; + requeueBuffers_ = std::queue{}; internalBuffers_.clear(); bufferList_.clear(); } +int RPiStream::queueToDevice(FrameBuffer *buffer) +{ + LOG(RPISTREAM, Debug) << "Queuing buffer " << buffer->cookie() + << " for " << name_; + + int ret = dev_->queueBuffer(buffer); + if (ret) + LOG(RPISTREAM, Error) << "Failed to queue buffer for " + << name_; + return ret; +} + } /* namespace RPi */ } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h index af9c2ad2..6222c867 100644 --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.h +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h @@ -52,6 +52,7 @@ public: private: void clearBuffers(); + int queueToDevice(FrameBuffer *buffer); /* * Indicates that this stream is active externally, i.e. the buffers * might be provided by (and returned to) the application. @@ -63,7 +64,7 @@ private: std::string name_; /* The actual device stream. */ std::unique_ptr dev_; - /* All framebuffers associated with this device stream. */ + /* All frame buffers associated with this device stream. */ std::vector bufferList_; /* * List of frame buffer that we can use if none have been provided by @@ -71,6 +72,15 @@ private: * buffers exported internally. */ std::queue availableBuffers_; + /* + * List of frame buffer that are to be re-queued into the device. + * A nullptr indicates any internal buffer can be used (from availableBuffers_), + * whereas a valid pointer indicates an external buffer to be queued. + * + * Ordering buffers to be queued is important here as it must match the + * requests coming from the application. + */ + std::queue requeueBuffers_; /* * This is a list of buffers exported internally. Need to keep this around * as the stream needs to maintain ownership of these buffers.