Show a patch.

GET /api/1.1/patches/1901/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1901,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/1901/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/1901/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20190829232653.13214-15-niklas.soderlund@ragnatech.se>",
    "date": "2019-08-29T23:26:53",
    "name": "[libcamera-devel,v2,14/14] libcamera: pipeline: rkisp1: Attach to an IPA",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "5a9e8fe1d60018ebd033512e0ab29b62da5684b3",
    "submitter": {
        "id": 5,
        "url": "https://patchwork.libcamera.org/api/1.1/people/5/?format=api",
        "name": "Niklas Söderlund",
        "email": "niklas.soderlund@ragnatech.se"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/1901/mbox/",
    "series": [
        {
            "id": 475,
            "url": "https://patchwork.libcamera.org/api/1.1/series/475/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=475",
            "date": "2019-08-29T23:26:40",
            "name": "libcamera: ipa: Add basic IPA support",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/475/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/1901/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/1901/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<niklas.soderlund@ragnatech.se>",
        "Received": [
            "from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net\n\t[195.74.38.229])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7705560C18\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 30 Aug 2019 01:27:40 +0200 (CEST)",
            "from bismarck.berto.se (unknown [79.202.45.17])\n\tby bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA\n\tid 93e34dbb-cab4-11e9-837a-0050569116f7;\n\tFri, 30 Aug 2019 01:27:33 +0200 (CEST)"
        ],
        "X-Halon-ID": "93e34dbb-cab4-11e9-837a-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": "Fri, 30 Aug 2019 01:26:53 +0200",
        "Message-Id": "<20190829232653.13214-15-niklas.soderlund@ragnatech.se>",
        "X-Mailer": "git-send-email 2.22.1",
        "In-Reply-To": "<20190829232653.13214-1-niklas.soderlund@ragnatech.se>",
        "References": "<20190829232653.13214-1-niklas.soderlund@ragnatech.se>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v2 14/14] libcamera: pipeline: rkisp1:\n\tAttach to an IPA",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.23",
        "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": "Thu, 29 Aug 2019 23:27:40 -0000"
    },
    "content": "Add the plumbing to the pipeline handler to interact with an IPA module.\nTo support this parameter and statistic buffers needs to be associated\nwith every request queued. The parameters buffer needs to be passed to\nthe IPA before any buffer in the request is queued to hardware and the\nstatistics buffer needs to be passed to the IPA for inspection as soon\nas it's ready.\n\nThis change makes the usage of an IPA module mandatory for the rkisp1\npipeline.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\n src/libcamera/pipeline/rkisp1/rkisp1.cpp | 263 ++++++++++++++++++++++-\n 1 file changed, 252 insertions(+), 11 deletions(-)",
    "diff": "diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\nindex de4ab523d0e4fe36..2bebf0eaf3877641 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n@@ -9,7 +9,7 @@\n #include <array>\n #include <iomanip>\n #include <memory>\n-#include <vector>\n+#include <queue>\n \n #include <linux/media-bus-format.h>\n \n@@ -34,7 +34,7 @@ class RkISP1CameraData : public CameraData\n {\n public:\n \tRkISP1CameraData(PipelineHandler *pipe)\n-\t\t: CameraData(pipe), sensor_(nullptr)\n+\t\t: CameraData(pipe, 1, 1), sensor_(nullptr)\n \t{\n \t}\n \n@@ -43,8 +43,21 @@ public:\n \t\tdelete sensor_;\n \t}\n \n+\tint initIPA() override;\n+\n \tStream stream_;\n \tCameraSensor *sensor_;\n+\n+private:\n+\tvoid updateSensor(V4L2ControlList controls);\n+\tvoid queueRequestHardware(const void *cookie);\n+};\n+\n+class RkISP1RequestData : public RequestData\n+{\n+public:\n+\tBuffer *stat;\n+\tBuffer *param;\n };\n \n class RkISP1CameraConfiguration : public CameraConfiguration\n@@ -99,18 +112,69 @@ private:\n \t\t\tPipelineHandler::cameraData(camera));\n \t}\n \n+\tfriend RkISP1CameraData;\n+\n \tint initLinks();\n \tint createCamera(MediaEntity *sensor);\n+\tvoid tryCompleteRequest(Request *request);\n \tvoid bufferReady(Buffer *buffer);\n+\tvoid statReady(Buffer *buffer);\n+\tvoid paramReady(Buffer *buffer);\n \n \tMediaDevice *media_;\n \tV4L2Subdevice *dphy_;\n \tV4L2Subdevice *isp_;\n \tV4L2VideoDevice *video_;\n+\tV4L2VideoDevice *stat_;\n+\tV4L2VideoDevice *param_;\n+\n+\tBufferPool statPool_;\n+\tBufferPool paramPool_;\n+\n+\tstd::queue<Buffer *> statBuffers_;\n+\tstd::queue<Buffer *> paramBuffers_;\n \n \tCamera *activeCamera_;\n };\n \n+int RkISP1CameraData::initIPA()\n+{\n+\tipa_->updateSensor.connect(this,\n+\t\t\t\t   &RkISP1CameraData::updateSensor);\n+\tipa_->queueRequest.connect(this,\n+\t\t\t\t   &RkISP1CameraData::queueRequestHardware);\n+\treturn 0;\n+}\n+\n+void RkISP1CameraData::updateSensor(V4L2ControlList controls)\n+{\n+\tsensor_->setControls(&controls);\n+}\n+\n+void RkISP1CameraData::queueRequestHardware(const void *cookie)\n+{\n+\t/* Translate cookie to request. */\n+\tRequest *request = reinterpret_cast<Request *>(const_cast<void *>(cookie));\n+\tPipelineHandlerRkISP1 *pipe =\n+\t\tstatic_cast<PipelineHandlerRkISP1 *>(pipe_);\n+\tRkISP1RequestData *reqData =\n+\t\tstatic_cast<RkISP1RequestData *>(request->data);\n+\tBuffer *buffer = request->findBuffer(&stream_);\n+\tint ret;\n+\n+\tret = pipe->param_->queueBuffer(reqData->param);\n+\tif (ret < 0)\n+\t\tLOG(RkISP1, Error) << \"Failed to queue parameters\";\n+\n+\tret = pipe->stat_->queueBuffer(reqData->stat);\n+\tif (ret < 0)\n+\t\tLOG(RkISP1, Error) << \"Failed to queue statistics\";\n+\n+\tret = pipe->video_->queueBuffer(buffer);\n+\tif (ret < 0)\n+\t\tLOG(RkISP1, Error) << \"Failed to queue video\";\n+}\n+\n RkISP1CameraConfiguration::RkISP1CameraConfiguration(Camera *camera,\n \t\t\t\t\t\t     RkISP1CameraData *data)\n \t: CameraConfiguration()\n@@ -202,12 +266,14 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n \n PipelineHandlerRkISP1::PipelineHandlerRkISP1(CameraManager *manager)\n \t: PipelineHandler(manager), dphy_(nullptr), isp_(nullptr),\n-\t  video_(nullptr)\n+\t  video_(nullptr), stat_(nullptr), param_(nullptr)\n {\n }\n \n PipelineHandlerRkISP1::~PipelineHandlerRkISP1()\n {\n+\tdelete param_;\n+\tdelete stat_;\n \tdelete video_;\n \tdelete isp_;\n \tdelete dphy_;\n@@ -317,6 +383,20 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n \tif (ret)\n \t\treturn ret;\n \n+\tV4L2DeviceFormat statFormat = {};\n+\tstatFormat.fourcc = V4L2_META_FMT_RK_ISP1_STAT_3A;\n+\n+\tret = stat_->setFormat(&statFormat);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tV4L2DeviceFormat paramFormat = {};\n+\tparamFormat.fourcc = V4L2_META_FMT_RK_ISP1_PARAMS;\n+\n+\tret = param_->setFormat(&paramFormat);\n+\tif (ret)\n+\t\treturn ret;\n+\n \tif (outputFormat.size != cfg.size ||\n \t    outputFormat.fourcc != cfg.pixelFormat) {\n \t\tLOG(RkISP1, Error)\n@@ -333,30 +413,92 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera,\n \t\t\t\t\t   const std::set<Stream *> &streams)\n {\n \tStream *stream = *streams.begin();\n+\tint ret;\n \n \tif (stream->memoryType() == InternalMemory)\n-\t\treturn video_->exportBuffers(&stream->bufferPool());\n+\t\tret = video_->exportBuffers(&stream->bufferPool());\n \telse\n-\t\treturn video_->importBuffers(&stream->bufferPool());\n+\t\tret = video_->importBuffers(&stream->bufferPool());\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tstatPool_.createBuffers(stream->configuration().bufferCount);\n+\tret = stat_->exportBuffers(&statPool_);\n+\tif (ret) {\n+\t\tvideo_->releaseBuffers();\n+\t\treturn ret;\n+\t}\n+\n+\tparamPool_.createBuffers(stream->configuration().bufferCount);\n+\tret = param_->exportBuffers(&paramPool_);\n+\tif (ret) {\n+\t\tstat_->releaseBuffers();\n+\t\tvideo_->releaseBuffers();\n+\t\treturn ret;\n+\t}\n+\n+\tfor (unsigned int i = 0; i < stream->configuration().bufferCount; i++) {\n+\t\tstatBuffers_.push(new Buffer(i));\n+\t\tparamBuffers_.push(new Buffer(i));\n+\t}\n+\n+\treturn ret;\n }\n \n int PipelineHandlerRkISP1::freeBuffers(Camera *camera,\n \t\t\t\t       const std::set<Stream *> &streams)\n {\n+\twhile (!paramBuffers_.empty())\n+\t\tparamBuffers_.pop();\n+\n+\twhile (!statBuffers_.empty())\n+\t\tstatBuffers_.pop();\n+\n+\tif (param_->releaseBuffers())\n+\t\tLOG(RkISP1, Error) << \"Failed to release parameters buffers\";\n+\n+\tif (stat_->releaseBuffers())\n+\t\tLOG(RkISP1, Error) << \"Failed to release stat buffers\";\n+\n \tif (video_->releaseBuffers())\n-\t\tLOG(RkISP1, Error) << \"Failed to release buffers\";\n+\t\tLOG(RkISP1, Error) << \"Failed to release video buffers\";\n \n \treturn 0;\n }\n \n int PipelineHandlerRkISP1::start(Camera *camera)\n {\n+\tRkISP1CameraData *data = cameraData(camera);\n \tint ret;\n \n+\tret = data->ipa_->initSensor(data->sensor_->controls());\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = param_->streamOn();\n+\tif (ret) {\n+\t\tLOG(RkISP1, Error)\n+\t\t\t<< \"Failed to start parameters \" << camera->name();\n+\t\treturn ret;\n+\t}\n+\n+\tret = stat_->streamOn();\n+\tif (ret) {\n+\t\tparam_->streamOff();\n+\t\tLOG(RkISP1, Error)\n+\t\t\t<< \"Failed to start statistics \" << camera->name();\n+\t\treturn ret;\n+\t}\n+\n \tret = video_->streamOn();\n-\tif (ret)\n+\tif (ret) {\n+\t\tparam_->streamOff();\n+\t\tstat_->streamOff();\n+\n \t\tLOG(RkISP1, Error)\n \t\t\t<< \"Failed to start camera \" << camera->name();\n+\t}\n \n \tactiveCamera_ = camera;\n \n@@ -372,6 +514,16 @@ void PipelineHandlerRkISP1::stop(Camera *camera)\n \t\tLOG(RkISP1, Warning)\n \t\t\t<< \"Failed to stop camera \" << camera->name();\n \n+\tret = stat_->streamOff();\n+\tif (ret)\n+\t\tLOG(RkISP1, Warning)\n+\t\t\t<< \"Failed to stop statistics \" << camera->name();\n+\n+\tret = param_->streamOff();\n+\tif (ret)\n+\t\tLOG(RkISP1, Warning)\n+\t\t\t<< \"Failed to stop parameters \" << camera->name();\n+\n \tactiveCamera_ = nullptr;\n }\n \n@@ -380,6 +532,16 @@ int PipelineHandlerRkISP1::queueRequest(Camera *camera, Request *request)\n \tRkISP1CameraData *data = cameraData(camera);\n \tStream *stream = &data->stream_;\n \n+\tif (paramBuffers_.empty()) {\n+\t\tLOG(RkISP1, Error) << \"Parameters buffer underrun\";\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tif (statBuffers_.empty()) {\n+\t\tLOG(RkISP1, Error) << \"Statistic buffer underrun\";\n+\t\treturn -ENOENT;\n+\t}\n+\n \tBuffer *buffer = request->findBuffer(stream);\n \tif (!buffer) {\n \t\tLOG(RkISP1, Error)\n@@ -387,12 +549,24 @@ int PipelineHandlerRkISP1::queueRequest(Camera *camera, Request *request)\n \t\treturn -ENOENT;\n \t}\n \n-\tint ret = video_->queueBuffer(buffer);\n-\tif (ret < 0)\n-\t\treturn ret;\n+\tRkISP1RequestData *reqData = new RkISP1RequestData();\n+\trequest->data = reqData;\n+\treqData->param = paramBuffers_.front();\n+\treqData->stat = statBuffers_.front();\n+\n+\tprepareInternalBuffer(reqData->param, request,\n+\t\t\t      &paramPool_.buffers()[reqData->param->index()]);\n+\tprepareInternalBuffer(reqData->stat, request,\n+\t\t\t      &statPool_.buffers()[reqData->stat->index()]);\n+\n+\tparamBuffers_.pop();\n+\tstatBuffers_.pop();\n \n \tPipelineHandler::queueRequest(camera, request);\n \n+\tdata->ipa_->processRequest(request, request->controls(),\n+\t\t\t\t   *reqData->param);\n+\n \treturn 0;\n }\n \n@@ -435,6 +609,10 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)\n \tstd::unique_ptr<RkISP1CameraData> data =\n \t\tutils::make_unique<RkISP1CameraData>(this);\n \n+\tdata->controlInfo_.emplace(std::piecewise_construct,\n+\t\t\t\t   std::forward_as_tuple(AeEnable),\n+\t\t\t\t   std::forward_as_tuple(AeEnable, false, true));\n+\n \tdata->sensor_ = new CameraSensor(sensor);\n \tret = data->sensor_->init();\n \tif (ret)\n@@ -478,7 +656,17 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator)\n \tif (video_->open() < 0)\n \t\treturn false;\n \n+\tstat_ = V4L2VideoDevice::fromEntityName(media_, \"rkisp1-statistics\");\n+\tif (stat_->open() < 0)\n+\t\treturn false;\n+\n+\tparam_ = V4L2VideoDevice::fromEntityName(media_, \"rkisp1-input-params\");\n+\tif (param_->open() < 0)\n+\t\treturn false;\n+\n \tvideo_->bufferReady.connect(this, &PipelineHandlerRkISP1::bufferReady);\n+\tstat_->bufferReady.connect(this, &PipelineHandlerRkISP1::statReady);\n+\tparam_->bufferReady.connect(this, &PipelineHandlerRkISP1::paramReady);\n \n \t/* Configure default links. */\n \tif (initLinks() < 0) {\n@@ -504,13 +692,66 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator)\n  * Buffer Handling\n  */\n \n+void PipelineHandlerRkISP1::tryCompleteRequest(Request *request)\n+{\n+\tRkISP1RequestData *reqData =\n+\t\tstatic_cast<RkISP1RequestData *>(request->data);\n+\n+\tif (reqData->param)\n+\t\treturn;\n+\n+\tif (reqData->stat)\n+\t\treturn;\n+\n+\tif (request->hasPendingBuffers())\n+\t\treturn;\n+\n+\tdelete reqData;\n+\trequest->data = nullptr;\n+\n+\tcompleteRequest(activeCamera_, request);\n+}\n+\n void PipelineHandlerRkISP1::bufferReady(Buffer *buffer)\n {\n \tASSERT(activeCamera_);\n \tRequest *request = buffer->request();\n \n \tcompleteBuffer(activeCamera_, request, buffer);\n-\tcompleteRequest(activeCamera_, request);\n+\ttryCompleteRequest(request);\n+}\n+\n+void PipelineHandlerRkISP1::statReady(Buffer *buffer)\n+{\n+\tASSERT(activeCamera_);\n+\tRkISP1CameraData *data = cameraData(activeCamera_);\n+\tRequest *request = buffer->request();\n+\tRkISP1RequestData *reqData =\n+\t\tstatic_cast<RkISP1RequestData *>(request->data);\n+\n+\tdata->ipa_->updateStatistics(request, *buffer);\n+\n+\t/* TODO: Fetch libcamera status controls from IPA */\n+\n+\treqData->stat = nullptr;\n+\n+\tstatBuffers_.push(buffer);\n+\n+\ttryCompleteRequest(request);\n+}\n+\n+void PipelineHandlerRkISP1::paramReady(Buffer *buffer)\n+{\n+\tASSERT(activeCamera_);\n+\tRequest *request = buffer->request();\n+\tRkISP1RequestData *reqData =\n+\t\tstatic_cast<RkISP1RequestData *>(request->data);\n+\n+\treqData->param = nullptr;\n+\n+\tparamBuffers_.push(buffer);\n+\n+\ttryCompleteRequest(request);\n }\n \n REGISTER_PIPELINE_HANDLER(PipelineHandlerRkISP1);\n",
    "prefixes": [
        "libcamera-devel",
        "v2",
        "14/14"
    ]
}