From patchwork Wed Jul 22 12:25:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8916 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 720D7BDB1B for ; Wed, 22 Jul 2020 12:26:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E5B4D60983; Wed, 22 Jul 2020 14:25:59 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="F8eXdXHE"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5DEF76053C for ; Wed, 22 Jul 2020 14:25:58 +0200 (CEST) Received: from pyrite.rasen.tech (unknown [IPv6:2400:4051:61:600:2c71:1b79:d06d:5032]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BE197329; Wed, 22 Jul 2020 14:25:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1595420753; bh=6w7Wbb7QigO4FFKun9TJOCHK77PZxDY9eCu5oRwoHVQ=; h=From:To:Cc:Subject:Date:From; b=F8eXdXHEqQByx+G0WNzQygTnT4jZjDsB0zCWFloF1oAYJcpYR7fsVpbSuF1vvjAdP wb4SkgygZ+wGSc8E+nBJRN/m7gBaZUBLVfspjAPuSGOZcPcrqk+8yWih2owRvEx6Bf ZtHOhyLrniB5AtI+vY+q/GIXxIrSJqV+ePElyKbc= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 22 Jul 2020 21:25:43 +0900 Message-Id: <20200722122543.119759-1-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH v2] [DO NOT MERGE] IPA: raspberrypi: Sample IPA data structure IDL definition and output 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" In this whole patch, keep in mind that whenever flatbuffers is mentioned, it could be replaced by anything else, such as protobuf. Also, in general, naming of anything is flexible. I tried to chose reasonable placeholders to show how things would work. I have not yet done the theoretical plumbing. I wanted to get this draft out first at least, before continuing too far without feedback. * Introduction raspberrypi.libcamera.decl shows a sample custom IPA data structure IDL definition for the raspberrypi pipeline handler. The intent is that I will implement a custom compiler that will compile this definition into flatbuffers, as well as the header that will be included in the pipeline handler and the IPA. flatbuffers will compile the flatbuffers definition into the flatbuffers header that the included header will use for serdes. The purpose of this custom IPA data structure definition is to allow pipeline handlers and IPAs to use custom data structures for configure, processEvent, and queueFrameAction, rather than the rigid IPAOperationData. Hooking it up with framebuffers, and the compiler that I inted to write, will implement serdes for these custom data structures that the IPAProxies can use. raspberrypi.fbs shows the intended output of the compiler that I intend to write, which will be in the input to the flatbuffers compiler. raspberrypi_wrapper.h shows the other intended output of the of the compiler that I inted to write. This is the header that will be included by the pipeline handler and the IPA. The structs that are defined in this header can be used directly by the pipeline handler and IPA, and the serialize function and the deserialization constructor are meant to be used by the IPAProxy (maybe they could be made private and IPAProxy into a friend class?). The custom compiler is necessary to place restrictions on the allowed data definitions and make the definitions cleaner based on the restrictions, as well as generate a header that is a wrapper around the flatbuffers-generated header for the pipeline handler and IPA to include. * Custom data definition file raspberrypi.libcamera.decl There are three different types of custom data structures that must be defined, for the three IPA functions that take IPAOperationData: - configure (for IPAInterface::configure()) - event (for IPAInterface::processEvent()) - action (for IPAInterface::queueFrameAction) Discussion point: should configure have a separate input and output data definition? Since all three have an "opcode" and a payload, that is all that needs to be defined. The opcodes can be seen in the enums ConfigOps, EventOps, and ActionOps. The payloads can be seen in the unions ConfigPayload, EventPayload, and ActionPayload. Since the opcodes are essentially selectors into the unions, which field of the union the opcode points to must be specified as shown in the enums. Discussion point: ConfigPayload will become an element in a vector, so there can be multiple instances of in in a single configure() call. Conversely, EventPayload and ActionPayload are scalars in processEvent() and queueFrameAction. Should they be vectorized like ConfigPayload? Discussion point: can unions be disallowed besides at the top level of the data definition tree in the payload? These opcode and payload definitions are the only required components of the custom data definition. Once these are satisfied, the rest of the file follows standard flatbuffers rules. Also, since flatbuffers structs are a bit of a pain, I've decided to only allow flatbuffers tables in the definition (flatbuffers structs are not allowed ). In C++ (and C if I ever have to implement that compiler too...) they're wrapped as structs, though. Unions cannot have unions as a direct child. * flatbuffers input file raspberrypi.fbs is the intended output with raspberrypi.libcamera.decl, as described above. Some things to note... - RPiConfigParameters is not flags. I decided that rather than scanning flags and parsing a vector payload based on that, it would be better to have a vector of opcode-payload pairs. - NONE needs to be added to enums to appease flatbuffers. One of the many reasons why I think we should have a custom data definition to make writing the data definition cleaner for developers. - In flatbuffers, primitives cannot be members of unions. I'll add a global header that defines wrappers around primitives. In the custom data definition they are allowed, though. My compiler shall convert them to the wrapper. - libcamera already comes with a really nice ControlList serdes. In the flatbuffers global header I'll add the ControlList definition that is seen here. It's just defined as a byte array, so we can use libcamera's ControlList serializer. It does need to be renamed, though. - As mentioned earlier, RPiConfigParams has a vector of opcode-payload pairs, while RPiEventParams and RPiActionParams have a single opcode-payload pair * Custom generated header raspberrypi_wrapper.h flatbuffers will compile the flatbuffers input file into a flatbuffers header that can be included. This file cannot be used directly by pipeline handlers and IPAs without them directly interfacing with flatbuffers and its API. Thus, a custom header will also be generated by the compiler that I'll implement. This custom header implements wrappers for the data structures defined in the custom data definition file for pipeline handlers and IPAs to use, as well as serialize and deserialize functions for the proxies to use. The intended output of this header can be seen in raspberrypi_wrapper.h. The structs and enums and unions defined in this header can be used by pipeline handlers and IPAs as-is (ie. no special API like flatbuffers). Discussion point: maybe make the serialize function and deserialization constructor private and make IPAProxy a friend class? A Serializable class is reference but never defined. This class is meant to simply have a serialize() function (deserialize is implemented as an overloaded constructor). This class might not even be necessary. There are a couple helpers for serializing and deserializing ControlList such that it can work well with the flatbuffers data structures. I got the implementation from the test for ControlSerializer. There are also a couple helpers for extracting the fds and injecting the fds. The fd extraction is meant to be done by the IPAProxy prior to serialization. The IPAProxy can then use sendmsg and recvmsg (or some similar facility) to send the fds across the process boundary. These fds can then be injected back into the object after it is deserialized and reconstructed. The extracted fds are saved in a queue, in post-order. Since the data container tree is the same before and after serdes, the order of the fds is guaranteed to match, as the fds are injected also in post-order. Serialization, deserialization, fd extraction, and fd injection are all implemented with recursion. The fd extraction and injection functions may or may not be be ommitted if no members in the data container tree contain no fds. This is TBD. There are a few rules for the compilation... - unions and enums are as-is - tables are compiled with its members as member variables, and have three constructors, 1) empty default, 2) define all members, and 3) deserialization constructor. They also get a serialize function that takes a flatbuffer builder and outputs a flatbuffer offset. This allows recursion to do serialization. Only the top-level (RPiConfigureParamsWrapper, RPiEventParamsWrapper, RPiActionParamsWrapper) tables get a serialize functions that takes void and returns a pair of byte array and length. - serialization is implemented as: - for every member variable: - if it is primitive, nop - if it is controls, call serializeControlList - if it is table, call table's serialize - if it is a vector, convert the vector to a vector of flatbuffer offsets by serializing every member based on the above three rules - if it is a union: - switch on opcode: - set union type based on opcode - set union content based on the same above four rules - call flatbuffer's create object with all the serialized members - deserialization is implemented as a constructor. top-level tables take a pointer to a byte array as input, while non-top-level tables take a pointer to a byte array casted to the flatbuffers object. If the table is used in a vector anywhere in the data definition, there will be another deserialization constructor that takes a flatbuffer offset. - cast input to flatbuffers offset (if necessary) - for every member variable: - if it is primitive, set the member variable - if it is controls, set member variable with deserializeControlList - if it is table, construct the table with the deserialization constructor, and set the member variable - if it is vector, convert the vector of flatbuffer offsets into the vector of the member variable by deserializing based on the above three rules - if it is union: - switch on opcode: - set member variable union content based on same above four rules - fd extraction is implemented as: - for every member variable: - if it is primitive or contols, nop - if it is table, extract the fds from the table, and add to extracted fds queue - if it is a vector, append the extracted fds for each element of the table, according to the above two rules - if it is a union: - switch on opcode: - append extracted fds according to above three rules - fd injection is implemented as the inverse of fd extraction, so instead of enqueueing the fds, the fds are dequeued and assigned Signed-off-by: Paul Elder --- Chanes in v2: - add fd support to inteded custom compiler output to ease the IPAProxy's job of extracting, sending the fds over the process boundary, and reinjecting the fds - add a declaration to the custom data definition to specify the ControlInfoMap (the ControlSerializer needs this) - add discussion point, if we can disallow unions in data definition outside of the top-level payload container In the commit message: - add paragraph about fd extraction and injection in "Custom generated header" section - remove paragraph about "fds not supported" in pre-introduction - add description of fd extraction and injection mechanism in compilation rules section of "Custom generated header" section --- include/libcamera/ipa/raspberrypi.fbs | 107 +++ include/libcamera/ipa/raspberrypi.h | 18 - .../libcamera/ipa/raspberrypi.libcamera.decl | 83 +++ include/libcamera/ipa/raspberrypi_wrapper.h | 658 ++++++++++++++++++ 4 files changed, 848 insertions(+), 18 deletions(-) create mode 100644 include/libcamera/ipa/raspberrypi.fbs create mode 100644 include/libcamera/ipa/raspberrypi.libcamera.decl create mode 100644 include/libcamera/ipa/raspberrypi_wrapper.h diff --git a/include/libcamera/ipa/raspberrypi.fbs b/include/libcamera/ipa/raspberrypi.fbs new file mode 100644 index 0000000..dcc1918 --- /dev/null +++ b/include/libcamera/ipa/raspberrypi.fbs @@ -0,0 +1,107 @@ +enum RPiConfigParameters:uint16 { + NONE = 0, + RPI_IPA_CONFIG_LS_TABLE, + RPI_IPA_CONFIG_STAGGERED_WRITE, + RPI_IPA_CONFIG_SENSOR, + RPI_IPA_CONFIG_SEND_FD, +} + +enum RPiEvents:uint16 { + NONE = 0, + RPI_IPA_EVENT_SIGNAL_STAT_READY, + RPI_IPA_EVENT_SIGNAL_ISP_PREPARE, + RPI_IPA_EVENT_QUEUE_REQUEST, + RPI_IPA_EVENT_SEND_FD, +} + +enum RPiActions:uint16 { + NONE = 0, + RPI_IPA_ACTION_V4L2_SET_STAGGERED, + RPI_IPA_ACTION_V4L2_SET_ISP, + RPI_IPA_ACTION_STATS_METADATA_COMPLETE, + RPI_IPA_ACTION_RUN_ISP, + RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME, + RPI_IPA_ACTION_EMBEDDED_COMPLETE, +} + +// TODO define this for all primitive types, and make global +table UnsignedInt { + value:uint32; +} + +table SignedInt { + value:int32; +} + +// TODO make this global +// TODO rename this +table ControlList { + list:[uint8]; +} + +// Data containers + +table RPiStaggeredWritePayload { + gainDelay:uint32; + exposureDelay:uint32; + sensorMetadata:uint32; +} + +table RPiIspPreparePayload { + embeddedbufferId:uint32; + bayerbufferId:uint32; +} + +table RPiStatsCompletePayload { + bufferId:uint32; + controls:ControlList; +} + + +// Payload unions + +union RPiConfigureUnion { + lsTableHandle:UnsignedInt, + staggeredWriteResult:RPiStaggeredWritePayload, + controls:ControlList, + bufferFd:SignedInt, +} + +table RPiConfigurePayload { + op:RPiConfigParameters; + payload:RPiConfigureUnion; +} + +union RPiEventPayload { + bufferId:UnsignedInt, + ispPrepare:RPiIspPreparePayload, + controls:ControlList, + bufferFd:SignedInt, +} + +union RPiActionPayload { + bufferId:UnsignedInt, + statsComplete:RPiStatsCompletePayload, + controls:ControlList, +} + + +// IPA function parameters + +table RPiConfigParams { + params:[RPiConfigurePayload]; +} + +table RPiEventParams { + ev:RPiEvents; + payload:RPiEventPayload; +} + +table RPiActionParams { + op:RPiActions; + payload:RPiActionPayload; +} + +root_type RPiConfigureParams; +root_type RPiEventParams; +root_type RPiActionParams; diff --git a/include/libcamera/ipa/raspberrypi.h b/include/libcamera/ipa/raspberrypi.h index a493776..69b3808 100644 --- a/include/libcamera/ipa/raspberrypi.h +++ b/include/libcamera/ipa/raspberrypi.h @@ -10,24 +10,6 @@ #include #include -enum RPiConfigParameters { - RPI_IPA_CONFIG_LS_TABLE = (1 << 0), - RPI_IPA_CONFIG_STAGGERED_WRITE = (1 << 1), - RPI_IPA_CONFIG_SENSOR = (1 << 2), -}; - -enum RPiOperations { - RPI_IPA_ACTION_V4L2_SET_STAGGERED = 1, - RPI_IPA_ACTION_V4L2_SET_ISP, - RPI_IPA_ACTION_STATS_METADATA_COMPLETE, - RPI_IPA_ACTION_RUN_ISP, - RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME, - RPI_IPA_ACTION_EMBEDDED_COMPLETE, - RPI_IPA_EVENT_SIGNAL_STAT_READY, - RPI_IPA_EVENT_SIGNAL_ISP_PREPARE, - RPI_IPA_EVENT_QUEUE_REQUEST, -}; - enum RPiIpaMask { ID = 0x0ffff, STATS = 0x10000, diff --git a/include/libcamera/ipa/raspberrypi.libcamera.decl b/include/libcamera/ipa/raspberrypi.libcamera.decl new file mode 100644 index 0000000..851ae6c --- /dev/null +++ b/include/libcamera/ipa/raspberrypi.libcamera.decl @@ -0,0 +1,83 @@ +namespace RPi; + +// this is necessary for de/serializeControlList() +// define in include/libcamera/ipa/raspberrypi.h +ControlInfoMap RPiControls; + +// opcodes +// these must be enums, and must be named as shown + +// required +// must specify which union option each value corresponds to +enum ConfigOps { + RPI_IPA_CONFIG_LS_TABLE:lsTableHandle, + RPI_IPA_CONFIG_STAGGERED_WRITE:staggeredWriteResult, + RPI_IPA_CONFIG_SENSOR:controls, + RPI_IPA_CONFIG_SEND_FD:bufferFd, +} + +// required +// must specify which union option each value corresponds to +enum EventOps { + RPI_IPA_EVENT_SIGNAL_STAT_READY:bufferId, + RPI_IPA_EVENT_SIGNAL_ISP_PREPARE:ispPrepare, + RPI_IPA_EVENT_QUEUE_REQUEST:controls, + RPI_IPA_EVENT_SEND_FD:bufferFd, +} + +// required +// must specify which union option each value corresponds to +enum ActionOps { + RPI_IPA_ACTION_V4L2_SET_STAGGERED:controls, + RPI_IPA_ACTION_V4L2_SET_ISP:controls, + RPI_IPA_ACTION_STATS_METADATA_COMPLETE:statsComplete, + RPI_IPA_ACTION_RUN_ISP:bufferId, + RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME:bufferId, + RPI_IPA_ACTION_EMBEDDED_COMPLETE:bufferId, +} + +// Custom Data containers + +table RPiStaggeredWritePayload { + gainDelay:uint32; + exposureDelay:uint32; + sensorMetadata:uint32; +} + +table RPiIspPreparePayload { + embeddedbufferId:uint32; + bayerbufferId:uint32; +} + +table RPiStatsCompletePayload { + bufferId:uint32; + controls:ControlList; +} + + +// First level payload unions +// these must be unions, and must be named as shown + +// required +// this one is actually in a vector of payload objects (op-union pair) +union ConfigPayload { + lsTableHandle:uint32, + staggeredWriteResult:RPiStaggeredWritePayload, + controls:ControlList, + bufferFd:int32, +} + +// required +union EventPayload { + bufferId:uint32, + ispPrepare:RPiIspPreparePayload, + controls:ControlList, + bufferFd:int32, +} + +// required +union ActionPayload { + bufferId:uint32, + statsComplete:RPiStatsCompletePayload, + controls:ControlList, +} diff --git a/include/libcamera/ipa/raspberrypi_wrapper.h b/include/libcamera/ipa/raspberrypi_wrapper.h new file mode 100644 index 0000000..eab51d3 --- /dev/null +++ b/include/libcamera/ipa/raspberrypi_wrapper.h @@ -0,0 +1,658 @@ +// will be automatically generated by custom compiler + +#ifndef __LIBCAMERA_IPA_INTERFACE_RASPBERRYPI_FB_H__ +#define __LIBCAMERA_IPA_INTERFACE_RASPBERRYPI_FB_H__ + +#include "raspberrypi_generated.h" + +namespace libcamera { + +// TODO this (and deserialize) should go global +inline flatbuffers::Offset serializeControlList(flatbuffers::FlatBufferBuilder &builder, ControlList &list) +{ + ControlSerializer serializer; + + // TODO need a way to get the info map (param? #defined param?) + size_t size = serializer.binarySize(RPiControls); + std::vector infoData(size); + ByteStreamBuffer buffer(infoData.data(), infoData.size()); + serializer.serialize(RPiControls, buffer); + + size = serializer.binarySize(list); + std::vector listData(size); + buffer = ByteStreamBuffer(listData.data(), listData.size()); + serializer.serialize(list, buffer); + + // don't need to error check; just write empty vector + return CreateControlListDirect(builder, listData); +} + +// TODO fix the input type for this (like ControlListFB or something?) +inline ControlList deserializeControlList(ControlList *obj) +{ + ControlSerializer deserializer; + std::vector buf = std::vector(obj->begin(), obj->end()); + + std::vector infoData(size); + BytesStreamBuffer buffer(const_cast(infoData.data()), infoData.size()); + ControlInfoMap infoMap = deserializer.deserialize(buffer); + // TODO what to do for error checking? + + std::vector listData(size); + buffer = ByteStreamBuffer(const_cast(listData.data()), listData.size()); + ControlList list = deserializer.deserialize(buffer); + + return list; +} + + +enum RPiConfigParametersWrapper { + RPI_IPA_CONFIG_LS_TABLE = 1, + RPI_IPA_CONFIG_STAGGERED_WRITE = 2, + RPI_IPA_CONFIG_SENSOR = 3, + RPI_IPA_CONFIG_SEND_FD = 4, +}; + +enum RPiEventsWrapper { + RPI_IPA_EVENT_SIGNAL_STAT_READY = 1, + RPI_IPA_EVENT_SIGNAL_ISP_PREPARE = 2, + RPI_IPA_EVENT_QUEUE_REQUEST = 3, + RPI_IPA_EVENT_SEND_FD = 4, +}; + +enum RPiActionsWrapper { + RPI_IPA_ACTION_V4L2_SET_STAGGERED, + RPI_IPA_ACTION_V4L2_SET_ISP, + RPI_IPA_ACTION_STATS_METADATA_COMPLETE, + RPI_IPA_ACTION_RUN_ISP, + RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME, + RPI_IPA_ACTION_EMBEDDED_COMPLETE, +}; + +struct RPiStaggeredWritePayloadWrapper : Serializable +{ + RPiStaggeredWritePayloadWrapper() {} + + RPiStaggeredWritePayloadWrapper(uint32_t gainDelay, uint32_t exposureDelay, uint32_t sensorMetadata) : gainDelay_(gainDelay), exposureDelay_(exposureDelay), sensorMetadata_(sensorMetadata) {} + + RPiStaggeredWritePayloadWrapper(const RPiStaggeredWritePayload *buf) + { + const RPiStaggeredWritePayload *obj = flatbuffers::GetRoot(buf); + + gainDelay_ = obj->gainDelay(); + exposureDelay_ = obj->exposureDelay(); + sensorMetadata_ = obj->sensorMetadata(); + } + + flatbuffers::Offset serialize(flatbuffers::FlatBufferBuilder &builder) + { + // - construct compound children depth-first + // - get simple data + // - feed to Create + + // nop for gainDelay_ + + // nop for exposureDelay_ + + // nop for sensorMetadata_ + + return CreateRPiStaggeredWritePayload(builder, gainDelay_, exposureDelay_, sensorMetadata_); + } + + std::deque extractFds() + { + // contains no fd and no compound children, so return empty + return {}; + } + + void injectFds(std::deque &fds) + { + // nop + } + + uint32_t gainDelay_; + uint32_t exposureDelay_; + uint32_t sensorMetadata_; +} + +struct RPiIspPreparePayloadWrapper : Serializable +{ + RPiIspPreparePayloadWrapper() {} + + RPiIspPreparePayloadWrapper(uint32_t embeddedbufferId, uint32_t bayerbufferId) : embeddedbufferId_(embeddedbufferId), bayerbufferId_(bayerbufferId) {} + + RPiIspPreparePayloadWrapper(const RPiIspPreparePayload *buf) + { + const RPiIspPreparePayload *obj = flatbuffers::GetRoot(buf); + + embeddedbufferId_ = obj->embeddedbufferId(); + bayerbufferId_ = obj->bayerbufferId(); + } + + flatbuffers::Offset serialize(flatbuffers::FlatBufferBuilder &builder) + { + // - construct compound children depth-first + // - get simple data + // - feed to Create + + // nop for embeddedbufferId_ + + // nop for bayerbufferId_ + + return CreateRPiIspPreparePayload(builder, embeddedbufferId_, bayerbufferId_); + } + + // these could be generated for every struct and not just those that + // fds in their tree. that'll save parsing the dependency graph in the + // compiler + std::deque extractFds() + { + return {}; + } + + void injectFds(std::deque &fds) + { + // nop + } + + uint32_t embeddedbufferId_; + uint32_t bayerbufferId_; +} + +struct RPiStatsCompletePayloadWrapper : Serializable +{ + RPiStatsCompletePayloadWrapper() {} + + RPiStatsCompletePayloadWrapper(uint32_t bufferId, ControlList &controls) : bufferId_(bufferId), controls_(controls) {} + + // deserialize + RPiStatsCompletePayloadWrapper(const RPiStatsCompletePayload *buf) + { + const RPiStatsCompletePayload *obj = flatbuffers::GetRoot(buf); + + bufferId_ = obj->bufferId(); + controls_ = deserializeControlList(obj->controls()); + } + + flatbuffers::Offset serialize(flatbuffers::FlatBufferBuilder &builder) + { + // - construct compound children depth-first + // - get simple data + // - feed to Create + + // nop for bufferId_ + + // serialize controls_ + flatbuffers::Offset controls = serializeControlList(builder, controls_); + + return CreateRPiStatsCompletePayload(builder, bufferId_, controls); + } + + uint32_t bufferId_; + ControlList controls_; +} + +union RPiConfigureUnionWrapper +{ + uint32_t lsTableHandle_; + RPiStaggeredWritePayload staggeredWriteResult_; + ControlList contols_; + int32_t bufferFd_; +} + +struct RPiConfigurePayloadWrapper : Serializable +{ + RPiConfigurePayloadWrapper() {} + + RPiConfigurePayloadWrapper(enum RPiConfigParametersWrapper op, RPiConfigureUnionWrapper payload) : op_(op), payload_(payload) {} + + // deserialize + RPiConfigurePayloadWrapper(const RPiConfigurePayload *buf) + { + // yeah fill this in if you want + } + + // deserialize + // TODO need this if is a member of vector + RPiConfigurePayloadWrapper(flatbuffers::Offset &p) + { + // nop for op + op_ = p.op(); + + // start of union block for payload_ + switch (op_) { + case RPI_IPA_CONFIG_LS_TABLE: + payload_.lsTableHandle_ = p.payload_as_lsTableHandle(); + break; + case RPI_IPA_CONFIG_STAGGERED_WRITE: + payload_.staggeredWriteResult_ = RPiStaggeredWritePayloadWrapper(p.payload_as_staggeredWriteResult); + break; + case RPI_IPA_CONFIG_SENSOR: + payload_.controls_ = deserializeControlList(p.payload_as_controls()); + break; + case RPI_IPA_CONFIG_SEND_FD: + payload_.bufferFd_ = p.payload_as_bufferFd(); + break; + } + // end of union block for payload_ + } + + flatbuffers::Offset serialize(flatbuffers::FlatBufferBuilder &builder) + { + // - construct compound children depth-first + // - get simple data + // - feed to Create + + // nop for op_ + RPiConfigureUnion payloadType; + flatbuffers::Offset payload; + + // start of union block for payload_ + switch (op_) { + case RPI_IPA_CONFIG_LS_TABLE: + payloadType = RPiConfigureUnion_lsTableHandle; + payload = CreateUnsignedInt(builder, payload_.lsTableHandle_); + break; + case RPI_IPA_CONFIG_STAGGERED_WRITE: + payloadType = RPiConfigureUnion_staggeredWriteResult; + payload = payload_.staggeredWriteResult_.serialize(builder); + break; + case RPI_IPA_CONFIG_SENSOR: + // controls + payloadType = RPiConfigureUnion_controls; + payload = serializeControlList(builder, payload_.controls_); + break; + case RPI_IPA_CONFIG_SEND_FD: + payloadType = RPiConfigureUnion_bufferFd; + payload = CreateSignedInt(builder, payload_.bufferFd_); + break; + } + // end of union block for payload_ + + return CreateRPiConfigurePayload(builder, op_, payloadType, payload); + } + + std::deque extractFds() + { + std::deque fds; + + // nop for op_, since it has no children, and is not fd + + // start of union block for payload_ + switch (op_) { + case RPI_IPA_CONFIG_LS_TABLE: + // value is not fd + break; + case RPI_IPA_CONFIG_STAGGERED_WRITE: + std::deque pfds = payload_.staggeredWriteResult_.extractFds(); + fds.insert(fds.end(), pfds,begin(), pfds.end()); + break; + case RPI_IPA_CONFIG_SENSOR: + // value is not fd + break; + case RPI_IPA_CONFIG_SEND_FD: + fds.push_back(payload.bufferFd_); + break; + } + // end of union block for payload_ + + return fds; + } + + void injectFds(std::deque &fds) + { + // nop for op_ + + // start of union block for payload_ + switch (op_) { + case RPI_IPA_CONFIG_LS_TABLE: + break; + case RPI_IPA_CONFIG_STAGGERED_WRITE: + payload_.staggeredWriteResult_.injectFds(fds); + break; + case RPI_IPA_CONFIG_SENSOR: + break; + case RPI_IPA_CONFIG_SEND_FD: + payload_.bufferFd_ = fds.at(0); + fds.pop_front(); + break; + } + // end of union block for payload_ + } + + enum RPiConfigParametersWrapper op_; + RPiConfigureUnionWrapper payload_; +} + +union RPiEventPayloadWrapper +{ + uint32_t bufferId_; + RPiIspPreparePayloadWrapper ispPrepare_; + ControlList controls_; + int32_t bufferFd_; +} + +union RPiActionPayloadWrapper +{ + uint32_t bufferId_; + RPiStatsCompletePayloadWrapper statsComplete_; + ControlList controls_; +} + +struct RPiConfigureParamsWrapper : Serializable +{ + RPiConfigureParamsWrapper() {} + + RPiConfigureParamsWrapper(std::vector payload) : payload_(payload) {} + + // deserialize + // only top-level gets fds + RPiConfigureParamsWrapper(const uint8_t *buf, std::dequeue fds) + { + const RPiConfigureParams *obj = flatbuffers::GetRoot(buf); + + // start of vector block for payload_ + flatbuffers::Vector> *payload = obj->params(); + std::transform(payload->begin(), payload->end(), std::back_inserter(payload_), + [](flatbuffers::Offset &p) -> RPiConfigurePayloadWrapper { + return RPiConfigurePayloadWrapper(p); + }); + // end of vector block for payload_ + + + // after constructing all the children, we need to inject the fds + injecetFds(fds); + } + + flatbuffers::Offset serialize(flatbuffers::FlatBufferBuilder &builder) + { + // - construct compound children depth-first + // - get simple data + // - feed to Create + + // start of vector block for payload_ + std::vector> payload; + std::transform(payload_.begin(), payload_.end(), std::back_inserter(payload), + [](RPiConfigurePayloadWrapper &p) -> flatbuffers::Offset { return p.serialize(builder); }); + // end of vector block for payload_ + + // use direct if there's vector as a member + return CreateRPiConfigureParamsDirect(builder, payload); + } + + // this is only for root_type + std::deque extractFds() + { + std::deque fds; + + // start of vector block for payload_ + for (RPiConfigurePayloadWrapper &payload : payload_) { + std::deque &pfds = payload_.extractFds(); + fds.insert(fds.end(), pfds.begin(), pfds.end()); + } + // end of vector block for payload_ + + return fds; + } + + void injectFds(std::deque &fds) + { + // start of vector block for payload_ + for (RPiConfigurePayloadWrapper &payload : payload_) + payload_.injectFds(fds); + // end of vector block for payload_ + } + + // this is only for root_type + // returns buffer pointer, buffer size (in bytes), and vector of fds + // the fds are matched by index; the index maps to full path in object + // tree, generated by the special compiler + std::tuple> serialize() + { + flatbuffers::FlatBufferBuilder builder(1024); + builder.Finish(this.serialize(builder)); + + uint8_t *buf = builder.GetBufferPointer(); + size_t size = builder.GetSize(); + return {buf, size, extractFds()}; + } + + std::vector payload_; +} + +struct RPiEventParamsWrapper : Serializable +{ + RPiEventParamsWrapper() {} + + RPiEventParamsWrapper(enum RPiEventsWrapper ev, RPiEventPayloadWrapper payload) : ev_(ev), payload_(payload) {} + + // deserialize + // root_type needs fds + RPiEventParamsWrapper(const uint8_t *buf, std::deque fds) + { + const RPiEventParams *obj = flatbuffers::GetRoot(buf); + + ev_ = obj->ev(); + + // start of union block for payload_ + switch (ev_) { + case RPI_IPA_EVENT_SIGNAL_STAT_READY: + payload_.bufferId_ = obj->payload_as_bufferId()->value(); + break; + case RPI_IPA_EVENT_SIGNAL_ISP_PREPARE: + payload_.ispPrepare_ = RPiIspPreparePayloadWrapper(obj->payload_as_ispPrepare()); + break; + case RPI_IPA_EVENT_QUEUE_REQUEST: + payload_.controls_ = deserializeControlList(obj->payload_as_controls()); + break; + case RPI_IPA_EVENT_SEND_FD: + payload_.bufferFd_ = obj->payload_as_bufferFd()->value(); + break; + } + // end of union block for payload_ + + injectFds(fds); + } + + flatbuffers::Offset serialize(flatbuffers::FlatBufferBuilder &builder) + { + // - construct compound children depth-first + // - get simple data + // - feed to Create + + // nop for ev_ + + // start of union block for payload_ + RPiEventPayload payloadType; + flatbuffers::Offset payload; + + switch (ev_) { + case RPI_IPA_EVENT_SIGNAL_STAT_READY: + payloadType = RPiEventPayload_bufferId; + payload = CreateUnsignedInt(builder, payload_.bufferId_); + break; + case RPI_IPA_EVENT_SIGNAL_ISP_PREPARE: + payloadType = RPiEventPayload_ispPrepare; + payload = payload_.ispPrepare_.serialize(builder); + break; + case RPI_IPA_EVENT_QUEUE_REQUEST: + payloadType = RPiEventPayload_controls; + payload = serializeControlList(builder, payload_.controls_); + break; + case RPI_IPA_EVENT_SEND_FD: + payloadType = RPiEventPayload_bufferFd; + payload = CreateSignedInt(builder, payload_.bufferFd_); + break; + } + // end of union block + + return CreateRPiEventParams(builder, ev_, payloadType, payload); + } + + std::deque extractFds() + { + std::deque fds; + + // nop for ev_ + + // start of union block for payload_ + switch (ev_) { + case RPI_IPA_EVENT_SIGNAL_STAT_READY: + // non-fd scalar + break; + case RPI_IPA_EVENT_SIGNAL_ISP_PREPARE: + std::deque &pfds = payload_.ispPrepare_.extractFds(); + fds.insert(fds.end(), pfds.begin(), pfds.end()); + break; + case RPI_IPA_EVENT_QUEUE_REQUEST: + // non-fd controls + break; + case RPI_IPA_EVENT_SEND_FD: + fds.push_back(payload_.bufferFd_); + break; + } + // end of union block for payload_ + + return fds; + } + + void injectFds(std::deque &fds) + { + // nop for ev_ + + // start of union block for payload_ + switch (ev_) { + case RPI_IPA_EVENT_SIGNAL_STAT_READY: + break; + case RPI_IPA_EVENT_SIGNAL_ISP_PREPARE: + payload_.ispPrepare_.injectFds(fds); + break; + case RPI_IPA_EVENT_QUEUE_REQUEST: + break; + case RPI_IPA_EVENT_SEND_FD: + payload_.bufferFd_ = fds.at(0); + fds.pop_front(); + break; + } + // end of union block for payload_ + } + + // this is only for root_type + // returns buffer pointer, buffer size (in bytes), and vector of fds + // the fds are matched by index; the index maps to full path in object + // tree, generated by the special compiler + std::tuple> serialize() + { + flatbuffers::FlatBufferBuilder builder(1024); + builder.Finish(this.serialize(builder)); + + uint8_t *buf = builder.GetBufferPointer(); + size_t size = builder.GetSize(); + return {buf, size, extractFds()}; + } + + enum RPiEventsWrapper ev_; + RPiEventPayloadWrapper payload_; +} + +struct RPiActionParamsWrapper : Serializable +{ + RPiActionParamsWrapper() {} + + RPiActionParamsWrapper(enum RPiActionsWrapper op, RPiActionPayloadWrapper payload) : op_(op), payload_(payload) {} + + // deserialize + // root_type needs fds + RPiActionParamsWrapper(const uint8_t *buf, std::deque &fds) + { + const RPiActionParams *obj = flatbuffers::GetRoot(buf); + + op_ = obj->op(); + + // start of union block for payload_ + switch (op_) { + case RPI_IPA_ACTION_V4L2_SET_STAGGERED: + case RPI_IPA_ACTION_V4L2_SET_ISP: + payload_.controls_ = deserializeControlList(obj->payload_as_controls()); + break; + case RPI_IPA_ACTION_STATS_METADATA_COMPLETE: + payload_.statsComplete_ = RPiStatsCompletePayloadWrapper(obj->payload_as_statsComplete()); + break; + case RPI_IPA_ACTION_RUN_ISP: + case RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME: + case RPI_IPA_ACTION_EMBEDDED_COMPLETE: + // UnsignedInt needs ->value() + payload_.bufferId_ = obj->payload_as_bufferId()->value(); + break; + } + // end of union block for payload_ + + injectFds(fds); + } + + flatbuffers::Offset serialize(flatbuffers::FlatBufferBuilder &builder) + { + // - construct compound children depth-first + // - get simple data + // - feed to Create + + // nop for op_ + + // start of union block for payload_ + RPiActionPayload payloadType; + flatbuffers::Offset payload; + + switch (op_) { + case RPI_IPA_ACTION_V4L2_SET_STAGGERED: + case RPI_IPA_ACTION_V4L2_SET_ISP: + payloadType = RPiActionPayload_controls; + payload = serializeControlList(builder, payload_.controls_); + break; + case RPI_IPA_ACTION_STATS_METADATA_COMPLETE: + payloadType = RPiActionPayload_statsComplete; + payload = payload_.statsComplete_.serialize(builder); + break; + case RPI_IPA_ACTION_RUN_ISP: + case RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME: + case RPI_IPA_ACTION_EMBEDDED_COMPLETE: + payloadType = RPiActionPayload_bufferId; + payload = CreateUnsignedInt(builder, payload_.bufferId_); + break; + } + // end of union block for payload_ + + return CreateRPiActionParams(builder, op_, payloadType, payload); + } + + // root_type needs it even if it's empty, because of top-level serialize() + std::deque extractFds() + { + return {}; + } + + std::deque injectFds() + { + // nop + } + + // this is only for root_type + // returns buffer pointer, buffer size (in bytes), and vector of fds + // the fds are matched by index; the index maps to full path in object + // tree, generated by the special compiler + std::tuple> serialize() + { + flatbuffers::FlatBufferBuilder builder(1024); + builder.Finish(this.serialize(builder)); + + uint8_t *buf = builder.GetBufferPointer(); + size_t size = builder.GetSize(); + return {buf, size, extractFds()}; + } + + enum RPiActionsWrapper op_; + RPiActionPayloadWrapper payload_; +} + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_INTERFACE_RASPBERRYPI_FB_H__ */