[libcamera-devel] [RFC PATCH v2 05/10] ipa: rkisp1: Use offset in mapping IPABuffer

Kieran Bingham kieran.bingham at ideasonboard.com
Wed Aug 25 23:19:19 CEST 2021



On 25/08/2021 21:49, Laurent Pinchart wrote:
> Hi Kieran,
> 
> On Tue, Aug 24, 2021 at 01:44:15PM +0100, Kieran Bingham wrote:
>> On 23/08/2021 23:55, Laurent Pinchart wrote:
>>> On Mon, Aug 23, 2021 at 10:12:16PM +0900, Hirokazu Honda wrote:
>>>> IPABuffer is represented by FrameBuffer. FrameBuffer::Plane has
>>>> now an offset. This uses the offset variable to map the IPABuffer.
>>>
>>> The commit message and subject line should be updated, this patch now
>>> moves to MappedFrameBuffer.
>>>
>>>> Signed-off-by: Hirokazu Honda <hiroh at chromium.org>
>>>> ---
>>>>  .../libcamera/internal/mapped_framebuffer.h   |  1 +
>>>>  src/ipa/rkisp1/rkisp1.cpp                     | 31 +++++++------------
>>>>  src/libcamera/mapped_framebuffer.cpp          |  7 +++++
>>>>  3 files changed, 19 insertions(+), 20 deletions(-)
>>>>
>>>> diff --git a/include/libcamera/internal/mapped_framebuffer.h b/include/libcamera/internal/mapped_framebuffer.h
>>>> index 42479541..ee0583d0 100644
>>>> --- a/include/libcamera/internal/mapped_framebuffer.h
>>>> +++ b/include/libcamera/internal/mapped_framebuffer.h
>>>> @@ -55,6 +55,7 @@ public:
>>>>  
>>>>  	using MapFlags = Flags<MapFlag>;
>>>>  
>>>> +	MappedFrameBuffer();
>>>>  	MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags);
>>>>  };
>>>>  
>>>> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
>>>> index 06fb9640..54cf2885 100644
>>>> --- a/src/ipa/rkisp1/rkisp1.cpp
>>>> +++ b/src/ipa/rkisp1/rkisp1.cpp
>>>> @@ -10,7 +10,6 @@
>>>>  #include <queue>
>>>>  #include <stdint.h>
>>>>  #include <string.h>
>>>> -#include <sys/mman.h>
>>>>  
>>>>  #include <linux/rkisp1-config.h>
>>>>  #include <linux/v4l2-controls.h>
>>>> @@ -24,6 +23,8 @@
>>>>  #include <libcamera/ipa/rkisp1_ipa_interface.h>
>>>>  #include <libcamera/request.h>
>>>>  
>>>> +#include <libcamera/internal/mapped_framebuffer.h>
>>>> +
>>>>  namespace libcamera {
>>>>  
>>>>  LOG_DEFINE_CATEGORY(IPARkISP1)
>>>> @@ -54,7 +55,7 @@ private:
>>>>  	void metadataReady(unsigned int frame, unsigned int aeState);
>>>>  
>>>>  	std::map<unsigned int, FrameBuffer> buffers_;
>>>> -	std::map<unsigned int, void *> buffersMemory_;
>>>> +	std::map<unsigned int, MappedFrameBuffer> mappedBuffers_;
>>>>  
>>>>  	ControlInfoMap ctrls_;
>>>>  
>>>> @@ -160,21 +161,10 @@ void IPARkISP1::mapBuffers(const std::vector<IPABuffer> &buffers)
>>>>  					     std::forward_as_tuple(buffer.planes));
>>>>  		const FrameBuffer &fb = elem.first->second;
>>>>  
>>>> -		/*
>>>> -		 * \todo Provide a helper to mmap() buffers (possibly exposed
>>>> -		 * to applications).
>>>> -		 */
>>>> -		buffersMemory_[buffer.id] = mmap(NULL,
>>>> -						 fb.planes()[0].length,
>>>> -						 PROT_READ | PROT_WRITE,
>>>> -						 MAP_SHARED,
>>>> -						 fb.planes()[0].fd.fd(),
>>>> -						 0);
>>>> -
>>>> -		if (buffersMemory_[buffer.id] == MAP_FAILED) {
>>>> -			int ret = -errno;
>>>> +		mappedBuffers_[buffer.id] = MappedFrameBuffer(&fb, MappedFrameBuffer::MapFlag::ReadWrite);
>>>
>>> We could use emplace() here to avoid the need for a default constructor,
>>> but we wouldn't be able to use operator[]() below, which isn't nice. I
>>> wonder if we could maybe store a std::unique_ptr<MappedFrameBuffer> in
>>> mappedBuffers_, to avoid the default constructor ?
>>>
>>> Kieran, you've designed the MappedFrameBuffer class, what do you think ?
>>
>> Hrm, firstly the error_ flag needs to be fixed up if there's a default
>> constructor - mentioned below in the Constructor code.
>>
>> But otherwise, even though we do have the isValid() check, I don't think
>> we have many users that actually check it.
>>
>> The aim was to make it simple and easy to create the mapping, which is
>> why it happens on construction.
>>
>> If this is causing problems, we can separate construction and mapping...
>> but then I'd expect to have map()/unmap() as well.
>> Looking at existing users of MappedFrameBuffer, I can see that:
>>
>>  IPAVimc::mapBuffers() currently uses emplace, (with a
>> piecewise_construct, to be able to specify the mapping flags as
>> read-only), and only uses find() to get them.
>>
>>
>> So does IPU3. ...
>>
>> And unsurprisingly, so does RPi.
>>
>>
>> However none of those implementations are checking the isValid() flag.
>> So perhaps they need to be updated to do so.
>>
>> And if we mandate that the isValid() should be checked, then it's not
>> much different to separating construction and mapping...
> 
> I like having construction and mapping grouped together, but you're
> right that separating them could indeed force users to check for errors
> (if we annotate the map() function with __nodiscard).

Yes, the point was to make it easy to use.

But if it's verging on promotion to an actual API exposed to
applications, it's worth considering correctness

>> The main goal for the current design is to allow other buffer types to
>> be constructed, so perhaps there could be a MappedDRMBuffer or
>> MappedDMABuffer or such.
>>
>> As long as that's kept in mind, I don't mind if the main interface
>> changes to suit needs as we determine them.
>>
>> Would using [], require checking the .isValid() flag at every usage?
>> (Because we might be given a new empty mapping, if the search failed?)
> 
> Not really, a user could be trusted to pass valid keys to operator[]().
> Storing the instances in a std::map<std::unique_ptr<MappedFrameBuffer>>
> as I've proposed would result in a null pointer dereference if the code
> tried to access an entry with an invalid key, which wouldn't be very
> different than using a default-constructed MappedFrameBuffer. We would
> "just" crash later in that case :-)

So I'm not opposed to supporting the [], as long as it doesn't lead to
potential mis-usages of a MappedFrameBuffer which aren't valid.

And the .at() works too.

> 
>> That might become less convenient ... ?
>>
>>> Apart from this,
>>>
>>> Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
>>>
>>>> +		if (!mappedBuffers_[buffer.id].isValid()) {
>>>>  			LOG(IPARkISP1, Fatal) << "Failed to mmap buffer: "
>>>> -					      << strerror(-ret);
>>>> +					      << strerror(mappedBuffers_[buffer.id].error());
>>>>  		}
>>>>  	}
>>>>  }
>>>> @@ -186,8 +176,7 @@ void IPARkISP1::unmapBuffers(const std::vector<unsigned int> &ids)
>>>>  		if (fb == buffers_.end())
>>>>  			continue;
>>>>  
>>>> -		munmap(buffersMemory_[id], fb->second.planes()[0].length);
>>>> -		buffersMemory_.erase(id);
>>>> +		mappedBuffers_.erase(id);
>>>>  		buffers_.erase(id);
>>>>  	}
>>>>  }
>>>> @@ -200,7 +189,8 @@ void IPARkISP1::processEvent(const RkISP1Event &event)
>>>>  		unsigned int bufferId = event.bufferId;
>>>>  
>>>>  		const rkisp1_stat_buffer *stats =
>>>> -			static_cast<rkisp1_stat_buffer *>(buffersMemory_[bufferId]);
>>>> +			reinterpret_cast<rkisp1_stat_buffer *>(
>>>> +				mappedBuffers_[bufferId].maps()[0].data());
>>>>  
>>>>  		updateStatistics(frame, stats);
>>>>  		break;
>>>> @@ -210,7 +200,8 @@ void IPARkISP1::processEvent(const RkISP1Event &event)
>>>>  		unsigned int bufferId = event.bufferId;
>>>>  
>>>>  		rkisp1_params_cfg *params =
>>>> -			static_cast<rkisp1_params_cfg *>(buffersMemory_[bufferId]);
>>>> +			reinterpret_cast<rkisp1_params_cfg *>(
>>>> +				mappedBuffers_[bufferId].maps()[0].data());
>>>>  
>>>>  		queueRequest(frame, params, event.controls);
>>>>  		break;
>>>> diff --git a/src/libcamera/mapped_framebuffer.cpp b/src/libcamera/mapped_framebuffer.cpp
>>>> index 03425dea..34d9564d 100644
>>>> --- a/src/libcamera/mapped_framebuffer.cpp
>>>> +++ b/src/libcamera/mapped_framebuffer.cpp
>>>> @@ -168,6 +168,13 @@ MappedBuffer::~MappedBuffer()
>>>>   * \brief A bitwise combination of MappedFrameBuffer::MapFlag values
>>>>   */
>>>>  
>>>> +/**
>>>> + * \brief Construct an empty MappedFrameBuffer
>>>> + */
>>>> +MappedFrameBuffer::MappedFrameBuffer()
>>>> +	: MappedBuffer()
>>>> +{
>>
>> If this is created, error_ would have to be set to an ... error here.
>>
>> Perhaps something like -ENOMEM, so that 'default constructed' empty
>> mappings are not 'valid'.
>>
>> That would then necessitate changine the ordering of how error_ is used,
>> currently it's only set when an error occurs on mapping.
>>
>> It would have to be set to 0 on successful mappings as well/instead.
>>
>>>> +}
>>>>  /**
>>>>   * \brief Map all planes of a FrameBuffer
>>>>   * \param[in] buffer FrameBuffer to be mapped
>>>
> 


More information about the libcamera-devel mailing list