[libcamera-devel] [PATCH] utils: ipc, raspberrypi: Make first output parameter direct return if int32

Laurent Pinchart laurent.pinchart at ideasonboard.com
Fri Mar 5 16:16:04 CET 2021


Hi Paul,

Thank you for the patch.

On Fri, Mar 05, 2021 at 06:31:46PM +0900, Paul Elder wrote:
> To make it more convenient for synchronous IPA calls to return a status,
> convert the first output into a direct return if it is an int32.
> 
> Convert the raspberrypi IPA interface and usage appropriately.
> 
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> 
> ---
> This is still an RFC until we decide what we want to do.
> 
> This patch depends on:
> - utils: ipc: Support custom parameters to init()
> - DEMO: raspberrypi: Use custom parameters to init()
> 
> I'm expecting to squash with the first patch. If we drop the second
> patch then we can remove the raspberrypi components from this patch.
> 
> I still need to update the IPA guide appropriately, but I decided to get
> approval on this RFC first.
> 
> Basically the only question (besides standard review) I want to ask is,
> should we squash this with "utils: ipc: Support custom parameters to
> init()"?

I'd keep this patch separate from "utils: ipc: Support custom parameters
to init()", and rebase the DEMO patch on top of the other two. This
patch could actually go before "utils: ipc: Support custom parameters to
init()" if it can help.

I think I'd split the RPi change out from this to a separate patch.

> Naush, does this (and "utils: ipc: Support custom parameters to init()")
> fit what you want?
> 
> ---
>  include/libcamera/ipa/raspberrypi.mojom       |  2 +-
>  src/ipa/raspberrypi/raspberrypi.cpp           | 44 +++++++++---------
>  .../pipeline/raspberrypi/raspberrypi.cpp      |  7 ++-
>  .../module_ipa_proxy.cpp.tmpl                 |  7 ++-
>  .../module_ipa_proxy_worker.cpp.tmpl          |  8 ++--
>  .../libcamera_templates/proxy_functions.tmpl  |  4 +-
>  .../generators/mojom_libcamera_generator.py   | 45 ++++++++++++-------
>  7 files changed, 64 insertions(+), 53 deletions(-)
> 
> diff --git a/include/libcamera/ipa/raspberrypi.mojom b/include/libcamera/ipa/raspberrypi.mojom
> index b8944227..99a62c02 100644
> --- a/include/libcamera/ipa/raspberrypi.mojom
> +++ b/include/libcamera/ipa/raspberrypi.mojom
> @@ -78,7 +78,7 @@ interface IPARPiInterface {
>  		  map<uint32, IPAStream> streamConfig,
>  		  map<uint32, ControlInfoMap> entityControls,
>  		  ConfigInput ipaConfig)
> -		=> (ConfigOutput results, int32 ret);
> +		=> (int32 ret, ConfigOutput results);
>  
>  	/**
>  	 * \fn mapBuffers()
> diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
> index 6a9aba6f..ac18dcbd 100644
> --- a/src/ipa/raspberrypi/raspberrypi.cpp
> +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> @@ -79,17 +79,17 @@ public:
>  			munmap(lsTable_, ipa::RPi::MaxLsGridSize);
>  	}
>  
> -	void init(const IPASettings &settings, const std::string &sensorName,
> -		  int *ret, bool *metadataSupport) override;
> +	int init(const IPASettings &settings, const std::string &sensorName,
> +		 bool *metadataSupport) override;
>  	void start(const ipa::RPi::StartControls &data,
>  		   ipa::RPi::StartControls *result) override;
>  	void stop() override {}
>  
> -	void configure(const CameraSensorInfo &sensorInfo,
> -		       const std::map<unsigned int, IPAStream> &streamConfig,
> -		       const std::map<unsigned int, ControlInfoMap> &entityControls,
> -		       const ipa::RPi::ConfigInput &data,
> -		       ipa::RPi::ConfigOutput *response, int32_t *ret) override;
> +	int configure(const CameraSensorInfo &sensorInfo,
> +		      const std::map<unsigned int, IPAStream> &streamConfig,
> +		      const std::map<unsigned int, ControlInfoMap> &entityControls,
> +		      const ipa::RPi::ConfigInput &data,
> +		      ipa::RPi::ConfigOutput *response) override;
>  	void mapBuffers(const std::vector<IPABuffer> &buffers) override;
>  	void unmapBuffers(const std::vector<unsigned int> &ids) override;
>  	void signalStatReady(const uint32_t bufferId) override;
> @@ -165,15 +165,15 @@ private:
>  	double maxFrameDuration_;
>  };
>  
> -void IPARPi::init(const IPASettings &settings, const std::string &sensorName,
> -		  int *ret, bool *metadataSupport)
> +int IPARPi::init(const IPASettings &settings, const std::string &sensorName,
> +		 bool *metadataSupport)
>  {
>  	LOG(IPARPI, Debug) << "sensor name is " << sensorName;
>  
>  	tuningFile_ = settings.configurationFile;
>  
>  	*metadataSupport = true;
> -	*ret = 0;
> +	return 0;
>  }
>  
>  void IPARPi::start(const ipa::RPi::StartControls &data,
> @@ -296,16 +296,15 @@ void IPARPi::setMode(const CameraSensorInfo &sensorInfo)
>  	mode_.max_frame_length = sensorInfo.maxFrameLength;
>  }
>  
> -void IPARPi::configure(const CameraSensorInfo &sensorInfo,
> -		       [[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,
> -		       const std::map<unsigned int, ControlInfoMap> &entityControls,
> -		       const ipa::RPi::ConfigInput &ipaConfig,
> -		       ipa::RPi::ConfigOutput *result, int32_t *ret)
> +int IPARPi::configure(const CameraSensorInfo &sensorInfo,
> +		      [[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,
> +		      const std::map<unsigned int, ControlInfoMap> &entityControls,
> +		      const ipa::RPi::ConfigInput &ipaConfig,
> +		      ipa::RPi::ConfigOutput *result)
>  {
>  	if (entityControls.size() != 2) {
>  		LOG(IPARPI, Error) << "No ISP or sensor controls found.";
> -		*ret = -1;
> -		return;
> +		return -1;
>  	}
>  
>  	result->params = 0;
> @@ -315,14 +314,12 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,
>  
>  	if (!validateSensorControls()) {
>  		LOG(IPARPI, Error) << "Sensor control validation failed.";
> -		*ret = -1;
> -		return;
> +		return -1;
>  	}
>  
>  	if (!validateIspControls()) {
>  		LOG(IPARPI, Error) << "ISP control validation failed.";
> -		*ret = -1;
> -		return;
> +		return -1;
>  	}
>  
>  	/* Setup a metadata ControlList to output metadata. */
> @@ -340,8 +337,7 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,
>  		if (!helper_) {
>  			LOG(IPARPI, Error) << "Could not create camera helper for "
>  					   << cameraName;
> -			*ret = -1;
> -			return;
> +			return -1;
>  		}
>  
>  		/*
> @@ -409,7 +405,7 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,
>  
>  	lastMode_ = mode_;
>  
> -	*ret = 0;
> +	return 0;
>  }
>  
>  void IPARPi::mapBuffers(const std::vector<IPABuffer> &buffers)
> diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> index a1c90028..106318ed 100644
> --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> @@ -1194,9 +1194,8 @@ int RPiCameraData::loadIPA()
>  
>  	IPASettings settings(ipa_->configurationFile(sensor_->model() + ".json"));
>  
> -	int ret;
>  	bool metadataSupport;
> -	ipa_->init(settings, "sensor name", &ret, &metadataSupport);
> +	int ret = ipa_->init(settings, "sensor name", &metadataSupport);
>  	LOG(RPI, Debug) << "metadata support " << (metadataSupport ? "yes" : "no");
>  	return ret;
>  }
> @@ -1254,8 +1253,8 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)
>  	/* Ready the IPA - it must know about the sensor resolution. */
>  	ipa::RPi::ConfigOutput result;
>  
> -	ipa_->configure(sensorInfo_, streamConfig, entityControls, ipaConfig,
> -			&result, &ret);
> +	ret = ipa_->configure(sensorInfo_, streamConfig, entityControls, ipaConfig,
> +			      &result);
>  

You can drop the blank line.

>  	if (ret < 0) {
>  		LOG(RPI, Error) << "IPA configuration failed!";
> diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
> index ff667ce0..167aaabd 100644
> --- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
> +++ b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
> @@ -212,7 +212,12 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data)
>  {%- endif %}
>  	}
>  {% if method|method_return_value != "void" %}
> -	return IPADataSerializer<{{method.response_parameters|first|name}}>::deserialize(_ipcOutputBuf.data(), 0);
> +	{{method|method_return_value}} _finalRet = IPADataSerializer<{{method|method_return_value}}>::deserialize(_ipcOutputBuf.data(), 0);

Maybe _retValue ?

> +
> +{{proxy_funcs.deserialize_call(method|method_param_outputs, '_ipcOutputBuf.data()', '_ipcOutputBuf.fds()', init_offset = method|method_return_value|byte_width|int)}}

Passing an offset feels a bit fragile to me. I think we could improve
the serializer API (possibly using span) in a way that would make it
more robust. That's out of scope for this patch though.

> +
> +	return _finalRet;
> +
>  {% elif method|method_param_outputs|length > 0 %}
>  {{proxy_funcs.deserialize_call(method|method_param_outputs, '_ipcOutputBuf.data()', '_ipcOutputBuf.fds()')}}
>  {% endif -%}
> diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl b/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl
> index d08af76d..c4206162 100644
> --- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl
> +++ b/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl
> @@ -85,15 +85,14 @@ public:
>  			{{param|name}} {{param.mojom_name}};
>  {% endfor %}
>  {%- if method|method_return_value != "void" %}
> -			{{method|method_return_value}} _callRet = ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}});
> -{%- else %}
> +			{{method|method_return_value}} _callRet =
> +{%- endif -%}
>  			ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}
>  {{- ", " if method|method_param_outputs|params_comma_sep -}}
>  {%- for param in method|method_param_outputs -%}
>  &{{param.mojom_name}}{{", " if not loop.last}}
>  {%- endfor -%}
>  );
> -{%- endif %}
>  {% if not method|is_async %}
>  			IPCMessage::Header header = { _ipcMessage.header().cmd, _ipcMessage.header().cookie };
>  			IPCMessage _response(header);
> @@ -102,9 +101,8 @@ public:
>  			std::tie(_callRetBuf, std::ignore) =
>  				IPADataSerializer<{{method|method_return_value}}>::serialize(_callRet);
>  			_response.data().insert(_response.data().end(), _callRetBuf.cbegin(), _callRetBuf.cend());
> -{%- else %}
> -		{{proxy_funcs.serialize_call(method|method_param_outputs, "_response.data()", "_response.fds()")|indent(16, true)}}
>  {%- endif %}
> +		{{proxy_funcs.serialize_call(method|method_param_outputs, "_response.data()", "_response.fds()")|indent(16, true)}}
>  			int _ret = socket_.send(_response.payload());
>  			if (_ret < 0) {
>  				LOG({{proxy_worker_name}}, Error)
> diff --git a/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl b/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl
> index f2d86b67..c2ac42fc 100644
> --- a/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl
> +++ b/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl
> @@ -135,8 +135,8 @@
>   #
>   # \todo Avoid intermediate vectors
>   #}
> -{%- macro deserialize_call(params, buf, fds, pointer = true, declare = false, iter = false, data_size = '') -%}
> -{% set ns = namespace(size_offset = 0) %}
> +{%- macro deserialize_call(params, buf, fds, pointer = true, declare = false, iter = false, data_size = '', init_offset = 0) -%}
> +{% set ns = namespace(size_offset = init_offset) %}
>  {%- if params|length > 1 %}
>  {%- for param in params %}
>  	[[maybe_unused]] const size_t {{param.mojom_name}}BufSize = readPOD<uint32_t>({{buf}}, {{ns.size_offset}}
> diff --git a/utils/ipc/generators/mojom_libcamera_generator.py b/utils/ipc/generators/mojom_libcamera_generator.py
> index fa0c21a2..e72a05ff 100644
> --- a/utils/ipc/generators/mojom_libcamera_generator.py
> +++ b/utils/ipc/generators/mojom_libcamera_generator.py
> @@ -149,10 +149,16 @@ def MethodParamInputs(method):
>      return method.parameters
>  
>  def MethodParamOutputs(method):
> -    if (MethodReturnValue(method) != 'void' or
> -        method.response_parameters is None):
> +    if method.response_parameters is None:
> +        return []
> +
> +    if MethodReturnValue(method) == 'void':
> +        return method.response_parameters
> +
> +    if len(method.response_parameters) <= 1:
>          return []
> -    return method.response_parameters
> +
> +    return method.response_parameters[1:]
>  
>  def MethodParamsHaveFd(parameters):
>      return len([x for x in parameters if HasFd(x)]) > 0
> @@ -167,11 +173,8 @@ def MethodParamNames(method):
>      params = []
>      for param in method.parameters:
>          params.append(param.mojom_name)
> -    if MethodReturnValue(method) == 'void':
> -        if method.response_parameters is None:
> -            return params
> -        for param in method.response_parameters:
> -            params.append(param.mojom_name)
> +    for param in MethodParamOutputs(method):
> +        params.append(param.mojom_name)
>      return params
>  
>  def MethodParameters(method):
> @@ -180,18 +183,17 @@ def MethodParameters(method):
>          params.append('const %s %s%s' % (GetNameForElement(param),
>                                           '&' if not IsPod(param) else '',
>                                           param.mojom_name))
> -    if MethodReturnValue(method) == 'void':
> -        if method.response_parameters is None:
> -            return params
> -        for param in method.response_parameters:
> -            params.append(f'{GetNameForElement(param)} *{param.mojom_name}')
> +    for param in MethodParamOutputs(method):
> +        params.append(f'{GetNameForElement(param)} *{param.mojom_name}')
>      return params
>  
>  def MethodReturnValue(method):
> -    if method.response_parameters is None:
> +    if method.response_parameters is None or len(method.response_parameters) == 0:
>          return 'void'
> -    if len(method.response_parameters) == 1 and IsPod(method.response_parameters[0]):
> -        return GetNameForElement(method.response_parameters[0])
> +    first_output = method.response_parameters[0]
> +    if ((len(method.response_parameters) == 1 and IsPod(first_output)) or
> +        first_output.kind == mojom.INT32):
> +        return GetNameForElement(first_output)
>      return 'void'

It's nice to see the flexibility in the generator :-)

>  
>  def IsAsync(method):
> @@ -237,6 +239,16 @@ def BitWidth(element):
>          return '32'
>      return ''
>  
> +def ByteWidthFromCppType(t):
> +    key = None
> +    for mojo_type, cpp_type in _kind_to_cpp_type.items():
> +        if t == cpp_type:
> +            key = mojo_type
> +    if key is None:
> +        raise Exception('invalid type')
> +    return str(int(int(_bit_widths[key]) / 8))

    return str(int(_bit_widths[key]) // 8)

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>

> +
> +
>  # Get the type name for a given element
>  def GetNameForElement(element):
>      # structs
> @@ -373,6 +385,7 @@ class Generator(generator.Generator):
>          libcamera_filters = {
>              'all_types': GetAllTypes,
>              'bit_width': BitWidth,
> +            'byte_width' : ByteWidthFromCppType,
>              'cap': Capitalize,
>              'choose': Choose,
>              'comma_sep': CommaSep,

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list