libcamera: controls: Add zero-copy set API for ControlValue

Extend the ControlValue class with a reserve() function to set the value
without actually copying data, and a non-const data() function that
allows writing data directly to the ControlValue storage. This allows
allocating memory directly in ControlValue, potentially removing a data
copy.

Note that this change was implemented before ByteStreamBuffer gained the
zero-copy read() variant, and doesn't actually save a copy in the
control serializer. It however still simplifies
ControlSerializer::loadControlValue().

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
This commit is contained in:
Laurent Pinchart 2020-02-28 17:01:43 +02:00
parent 9ab024f7c2
commit 8daf20485b
4 changed files with 50 additions and 72 deletions

View file

@ -115,6 +115,7 @@ public:
bool isArray() const { return isArray_; } bool isArray() const { return isArray_; }
std::size_t numElements() const { return numElements_; } std::size_t numElements() const { return numElements_; }
Span<const uint8_t> data() const; Span<const uint8_t> data() const;
Span<uint8_t> data();
std::string toString() const; std::string toString() const;
@ -174,6 +175,9 @@ public:
value.data(), value.size(), sizeof(typename T::value_type)); value.data(), value.size(), sizeof(typename T::value_type));
} }
void reserve(ControlType type, bool isArray = false,
std::size_t numElements = 1);
private: private:
ControlType type_ : 8; ControlType type_ : 8;
bool isArray_; bool isArray_;

View file

@ -295,70 +295,17 @@ int ControlSerializer::serialize(const ControlList &list,
return 0; return 0;
} }
template<typename T>
ControlValue ControlSerializer::loadControlValue(ByteStreamBuffer &buffer,
bool isArray,
unsigned int count)
{
ControlValue value;
const T *data = buffer.read<T>(count);
if (!data)
return value;
if (isArray)
value.set(Span<const T>{ data, count });
else
value.set(*data);
return value;
}
template<>
ControlValue ControlSerializer::loadControlValue<std::string>(ByteStreamBuffer &buffer,
bool isArray,
unsigned int count)
{
ControlValue value;
const char *data = buffer.read<char>(count);
if (!data)
return value;
value.set(std::string{ data, count });
return value;
}
ControlValue ControlSerializer::loadControlValue(ControlType type, ControlValue ControlSerializer::loadControlValue(ControlType type,
ByteStreamBuffer &buffer, ByteStreamBuffer &buffer,
bool isArray, bool isArray,
unsigned int count) unsigned int count)
{ {
switch (type) { ControlValue value;
case ControlTypeBool:
return loadControlValue<bool>(buffer, isArray, count);
case ControlTypeByte: value.reserve(type, isArray, count);
return loadControlValue<uint8_t>(buffer, isArray, count); buffer.read(value.data());
case ControlTypeInteger32: return value;
return loadControlValue<int32_t>(buffer, isArray, count);
case ControlTypeInteger64:
return loadControlValue<int64_t>(buffer, isArray, count);
case ControlTypeFloat:
return loadControlValue<float>(buffer, isArray, count);
case ControlTypeString:
return loadControlValue<std::string>(buffer, isArray, count);
case ControlTypeNone:
return ControlValue();
}
return ControlValue();
} }
ControlInfo ControlSerializer::loadControlInfo(ControlType type, ControlInfo ControlSerializer::loadControlInfo(ControlType type,

View file

@ -189,6 +189,15 @@ Span<const uint8_t> ControlValue::data() const
return { data, size }; return { data, size };
} }
/**
* \copydoc ControlValue::data() const
*/
Span<uint8_t> ControlValue::data()
{
Span<const uint8_t> data = const_cast<const ControlValue *>(this)->data();
return { const_cast<uint8_t *>(data.data()), data.size() };
}
/** /**
* \brief Assemble and return a string describing the value * \brief Assemble and return a string describing the value
* \return A string describing the ControlValue * \return A string describing the ControlValue
@ -312,23 +321,44 @@ void ControlValue::set(ControlType type, bool isArray, const void *data,
{ {
ASSERT(elementSize == ControlValueSize[type]); ASSERT(elementSize == ControlValueSize[type]);
release(); reserve(type, isArray, numElements);
Span<uint8_t> storage = ControlValue::data();
memcpy(storage.data(), data, storage.size());
}
/**
* \brief Set the control type and reserve memory
* \param[in] type The control type
* \param[in] isArray True to make the value an array
* \param[in] numElements The number of elements
*
* This function sets the type of the control value to \a type, and reserves
* memory to store the control value. If \a isArray is true, the instance
* becomes an array control and storage for \a numElements is reserved.
* Otherwise the instance becomes a simple control, numElements is ignored, and
* storage for the single element is reserved.
*/
void ControlValue::reserve(ControlType type, bool isArray, std::size_t numElements)
{
if (!isArray)
numElements = 1;
std::size_t oldSize = numElements_ * ControlValueSize[type_];
std::size_t newSize = numElements * ControlValueSize[type];
if (oldSize != newSize)
release();
type_ = type; type_ = type;
numElements_ = numElements;
isArray_ = isArray; isArray_ = isArray;
numElements_ = numElements;
std::size_t size = elementSize * numElements; if (oldSize == newSize)
void *storage; return;
if (size > sizeof(value_)) { if (newSize > sizeof(value_))
storage_ = reinterpret_cast<void *>(new uint8_t[size]); storage_ = reinterpret_cast<void *>(new uint8_t[newSize]);
storage = storage_;
} else {
storage = reinterpret_cast<void *>(&value_);
}
memcpy(storage, data, size);
} }
/** /**

View file

@ -40,9 +40,6 @@ private:
static void store(const ControlValue &value, ByteStreamBuffer &buffer); static void store(const ControlValue &value, ByteStreamBuffer &buffer);
static void store(const ControlInfo &info, ByteStreamBuffer &buffer); static void store(const ControlInfo &info, ByteStreamBuffer &buffer);
template<typename T>
ControlValue loadControlValue(ByteStreamBuffer &buffer, bool isArray,
unsigned int count);
ControlValue loadControlValue(ControlType type, ByteStreamBuffer &buffer, ControlValue loadControlValue(ControlType type, ByteStreamBuffer &buffer,
bool isArray = false, unsigned int count = 1); bool isArray = false, unsigned int count = 1);
ControlInfo loadControlInfo(ControlType type, ByteStreamBuffer &buffer); ControlInfo loadControlInfo(ControlType type, ByteStreamBuffer &buffer);