{"id":3899,"url":"https://patchwork.libcamera.org/api/patches/3899/?format=json","web_url":"https://patchwork.libcamera.org/patch/3899/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20200602013909.3170593-11-niklas.soderlund@ragnatech.se>","date":"2020-06-02T01:39:09","name":"[libcamera-devel,10/10] libcamera: ipu3: Allow zero-copy RAW stream capture","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"21ef8d15537552367eac3a93d882997b72290c7d","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/?format=json","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/3899/mbox/","series":[{"id":943,"url":"https://patchwork.libcamera.org/api/series/943/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=943","date":"2020-06-02T01:38:59","name":"libcamera: ipu3: Allow zero-copy RAW stream","version":1,"mbox":"https://patchwork.libcamera.org/series/943/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/3899/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/3899/checks/","tags":{},"headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net\n\t[195.74.38.228])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 866196113D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  2 Jun 2020 03:39:34 +0200 (CEST)","from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de\n\t[79.202.35.146]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA\n\tid d7e63e55-a471-11ea-a73e-0050569116f7;\n\tTue, 02 Jun 2020 03:39:05 +0200 (CEST)"],"X-Halon-ID":"d7e63e55-a471-11ea-a73e-0050569116f7","Authorized-sender":"niklas@soderlund.pp.se","From":"=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","To":"libcamera-devel@lists.libcamera.org","Date":"Tue,  2 Jun 2020 03:39:09 +0200","Message-Id":"<20200602013909.3170593-11-niklas.soderlund@ragnatech.se>","X-Mailer":"git-send-email 2.26.2","In-Reply-To":"<20200602013909.3170593-1-niklas.soderlund@ragnatech.se>","References":"<20200602013909.3170593-1-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH 10/10] libcamera: ipu3: Allow zero-copy\n\tRAW stream capture","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Tue, 02 Jun 2020 01:39:35 -0000"},"content":"With the refactored CIO2 interface it's now easy to add zero-copy for\nbuffers in the RAW stream. Use the internally allocated buffers inside\nthe CIO2Device if no buffer for the RAW stream is provided by the\napplication, or use the application provided one if one is.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\n src/libcamera/pipeline/ipu3/cio2.cpp | 52 +++++++++++--------\n src/libcamera/pipeline/ipu3/cio2.h   |  6 +--\n src/libcamera/pipeline/ipu3/ipu3.cpp | 76 +++++++++++-----------------\n 3 files changed, 62 insertions(+), 72 deletions(-)","diff":"diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp\nindex 895848d2b3a1fba9..bbf18910c0e7abd4 100644\n--- a/src/libcamera/pipeline/ipu3/cio2.cpp\n+++ b/src/libcamera/pipeline/ipu3/cio2.cpp\n@@ -205,31 +205,16 @@ int CIO2Device::exportBuffers(unsigned int count,\n \treturn output_->exportBuffers(count, buffers);\n }\n \n-FrameBuffer *CIO2Device::getBuffer()\n-{\n-\tif (availableBuffers_.empty()) {\n-\t\tLOG(IPU3, Error) << \"CIO2 buffer underrun\";\n-\t\treturn nullptr;\n-\t}\n-\n-\tFrameBuffer *buffer = availableBuffers_.front();\n-\n-\tavailableBuffers_.pop();\n-\n-\treturn buffer;\n-}\n-\n-void CIO2Device::putBuffer(FrameBuffer *buffer)\n-{\n-\tavailableBuffers_.push(buffer);\n-}\n-\n int CIO2Device::start()\n {\n-\tint ret = output_->allocateBuffers(CIO2_BUFFER_COUNT, &buffers_);\n+\tint ret = output_->exportBuffers(CIO2_BUFFER_COUNT, &buffers_);\n \tif (ret < 0)\n \t\treturn ret;\n \n+\tret = output_->importBuffers(CIO2_BUFFER_COUNT);\n+\tif (ret)\n+\t\tLOG(IPU3, Error) << \"Failed to import CIO2 buffers\";\n+\n \tfor (std::unique_ptr<FrameBuffer> &buffer : buffers_)\n \t\tavailableBuffers_.push(buffer.get());\n \n@@ -253,11 +238,36 @@ int CIO2Device::stop()\n \treturn ret;\n }\n \n-int CIO2Device::queueBuffer(FrameBuffer *buffer)\n+int CIO2Device::queueBuffer(Request *request, FrameBuffer *rawBuffer)\n {\n+\tFrameBuffer *buffer = rawBuffer;\n+\n+\t/* If no buffer provided in request, use an internal one. */\n+\tif (!buffer) {\n+\t\tif (availableBuffers_.empty()) {\n+\t\t\tLOG(IPU3, Error) << \"CIO2 buffer underrun\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tbuffer = availableBuffers_.front();\n+\t\tavailableBuffers_.pop();\n+\t}\n+\n+\tbuffer->setRequest(request);\n+\n \treturn output_->queueBuffer(buffer);\n }\n \n+void CIO2Device::tryReturnBuffer(FrameBuffer *buffer)\n+{\n+\tfor (const std::unique_ptr<FrameBuffer> &buf : buffers_) {\n+\t\tif (buf.get() == buffer) {\n+\t\t\tavailableBuffers_.push(buffer);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+}\n+\n V4L2PixelFormat CIO2Device::mediaBusToFormat(unsigned int code)\n {\n \tswitch (code) {\ndiff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h\nindex 032b91c082889a63..1a9b700bf4e7e15c 100644\n--- a/src/libcamera/pipeline/ipu3/cio2.h\n+++ b/src/libcamera/pipeline/ipu3/cio2.h\n@@ -47,9 +47,6 @@ public:\n \tint exportBuffers(unsigned int count,\n \t\t\t  std::vector<std::unique_ptr<FrameBuffer>> *buffers);\n \n-\tFrameBuffer *getBuffer();\n-\tvoid putBuffer(FrameBuffer *buffer);\n-\n \tint start();\n \tint stop();\n \n@@ -57,7 +54,8 @@ public:\n \tSize resolution() const { return sensor_->resolution(); }\n \tControlList properties() const { return sensor_->properties(); }\n \n-\tint queueBuffer(FrameBuffer *buffer);\n+\tint queueBuffer(Request *request, FrameBuffer *rawBuffer);\n+\tvoid tryReturnBuffer(FrameBuffer *buffer);\n \tSignal<FrameBuffer *> bufferReady;\n \n private:\ndiff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\nindex 636c1c54627b5777..03e954d0f30d39cc 100644\n--- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n@@ -121,7 +121,6 @@ public:\n \t}\n \n \tvoid imguOutputBufferReady(FrameBuffer *buffer);\n-\tvoid imguInputBufferReady(FrameBuffer *buffer);\n \tvoid cio2BufferReady(FrameBuffer *buffer);\n \n \tCIO2Device cio2_;\n@@ -730,25 +729,31 @@ void PipelineHandlerIPU3::stop(Camera *camera)\n int PipelineHandlerIPU3::queueRequestDevice(Camera *camera, Request *request)\n {\n \tIPU3CameraData *data = cameraData(camera);\n-\tFrameBuffer *buffer;\n \tint error = 0;\n \n-\t/* Get a CIO2 buffer, associate it with the request and queue it. */\n-\tbuffer = data->cio2_.getBuffer();\n-\tif (!buffer)\n-\t\treturn -EINVAL;\n+\t/* Search for a RAW buffer in the request, if any. */\n+\tFrameBuffer *rawBuffer = nullptr;\n+\tfor (auto it : request->buffers()) {\n+\t\tIPU3Stream *stream = static_cast<IPU3Stream *>(it.first);\n+\t\tif (!stream->raw_)\n+\t\t\tcontinue;\n \n-\tbuffer->setRequest(request);\n-\tdata->cio2_.queueBuffer(buffer);\n+\t\trawBuffer = it.second;\n+\t\tbreak;\n+\t}\n \n+\t/* Queue a buffer on the CIO2, the buffer may come from the request. */\n+\terror = data->cio2_.queueBuffer(request, rawBuffer);\n+\tif (error)\n+\t\treturn error;\n+\n+\t/* Queue all buffers from the request aimed for the ImgU. */\n \tfor (auto it : request->buffers()) {\n \t\tIPU3Stream *stream = static_cast<IPU3Stream *>(it.first);\n-\t\tbuffer = it.second;\n-\n-\t\t/* Skip raw streams, they are copied from the CIO2 buffer. */\n \t\tif (stream->raw_)\n \t\t\tcontinue;\n \n+\t\tFrameBuffer *buffer = it.second;\n \t\tint ret = stream->device_->dev->queueBuffer(buffer);\n \t\tif (ret < 0)\n \t\t\terror = ret;\n@@ -878,8 +883,8 @@ int PipelineHandlerIPU3::registerCameras()\n \t\t */\n \t\tdata->cio2_.bufferReady.connect(data.get(),\n \t\t\t\t\t&IPU3CameraData::cio2BufferReady);\n-\t\tdata->imgu_->input_->bufferReady.connect(data.get(),\n-\t\t\t\t\t&IPU3CameraData::imguInputBufferReady);\n+\t\tdata->imgu_->input_->bufferReady.connect(&data->cio2_,\n+\t\t\t\t\t&CIO2Device::tryReturnBuffer);\n \t\tdata->imgu_->output_.dev->bufferReady.connect(data.get(),\n \t\t\t\t\t&IPU3CameraData::imguOutputBufferReady);\n \t\tdata->imgu_->viewfinder_.dev->bufferReady.connect(data.get(),\n@@ -908,22 +913,6 @@ int PipelineHandlerIPU3::registerCameras()\n  * Buffer Ready slots\n  */\n \n-/**\n- * \\brief Handle buffers completion at the ImgU input\n- * \\param[in] buffer The completed buffer\n- *\n- * Buffers completed from the ImgU input are immediately queued back to the\n- * CIO2 unit to continue frame capture.\n- */\n-void IPU3CameraData::imguInputBufferReady(FrameBuffer *buffer)\n-{\n-\t/* \\todo Handle buffer failures when state is set to BufferError. */\n-\tif (buffer->metadata().status == FrameMetadata::FrameCancelled)\n-\t\treturn;\n-\n-\tcio2_.putBuffer(buffer);\n-}\n-\n /**\n  * \\brief Handle buffers completion at the ImgU output\n  * \\param[in] buffer The completed buffer\n@@ -956,27 +945,20 @@ void IPU3CameraData::cio2BufferReady(FrameBuffer *buffer)\n \t\treturn;\n \n \tRequest *request = buffer->request();\n-\tFrameBuffer *raw = request->findBuffer(&rawStream_);\n \n-\tif (!raw) {\n-\t\t/* No RAW buffers present, just queue to IMGU. */\n-\t\timgu_->input_->queueBuffer(buffer);\n-\t\treturn;\n-\t}\n-\n-\t/* RAW buffers present, special care is needed. */\n-\tif (request->buffers().size() > 1)\n-\t\timgu_->input_->queueBuffer(buffer);\n-\n-\tif (raw->copyFrom(buffer))\n-\t\tLOG(IPU3, Debug) << \"Copy of FrameBuffer failed\";\n-\n-\tpipe_->completeBuffer(camera_, request, raw);\n-\n-\tif (request->buffers().size() == 1) {\n-\t\tcio2_.putBuffer(buffer);\n+\t/*\n+\t * If the requests contains a buffer for the RAW stream and the buffer\n+\t * completed by the CIO2 satisfy all pending buffers in the request\n+\t * complete the request now, there is no need for this request to be\n+\t * processed by the ImGU.\n+\t */\n+\tif (request->findBuffer(&rawStream_) &&\n+\t    pipe_->completeBuffer(camera_, request, buffer)) {\n \t\tpipe_->completeRequest(camera_, request);\n+\t\treturn;\n \t}\n+\n+\timgu_->input_->queueBuffer(buffer);\n }\n \n /* -----------------------------------------------------------------------------\n","prefixes":["libcamera-devel","10/10"]}