From 207c9e1c1d73dc062d68bf0dbb27a0b58c7581a2 Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Wed, 3 Aug 2022 19:51:06 +0900 Subject: utils: ipc: Add support for Flags Add Flags as a supported type in the IPA interface. It is used in mojom with the [flags] attribute. Any field or parameter type E that is prefixed with the [flags] attribute will direct the code generator to generate the type name "Flags" and appropriate serialization/deserialization code for Flags instead of for E. It is usable and has been tested in struct members, function input and output parameters, and Signal parameters. This does not add support for returning Flags as direct return values. Additionally, the [scopedEnum] attribute can be used on enum definitions, which will instruct the code generator to convert it to an enum class instead of a raw enum. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- include/libcamera/ipa/core.mojom | 9 +++++ include/libcamera/ipa/ipa_interface.h | 1 + .../libcamera_templates/definition_functions.tmpl | 2 +- .../module_ipa_interface.h.tmpl | 2 +- .../libcamera_templates/module_ipa_proxy.h.tmpl | 2 +- .../libcamera_templates/proxy_functions.tmpl | 10 ++++-- .../generators/libcamera_templates/serializer.tmpl | 6 ++++ utils/ipc/generators/mojom_libcamera_generator.py | 41 +++++++++++++++++++--- 8 files changed, 62 insertions(+), 11 deletions(-) diff --git a/include/libcamera/ipa/core.mojom b/include/libcamera/ipa/core.mojom index 2bc3028c..33b8abed 100644 --- a/include/libcamera/ipa/core.mojom +++ b/include/libcamera/ipa/core.mojom @@ -33,6 +33,15 @@ module libcamera; * available for the type and there's no need to generate one * - hasFd - struct fields or empty structs only * - Designate that this field or empty struct contains a SharedFD + * - scopedEnum - enum definitions + * - Designate that this enum should be an enum class, as opposed to a pure + * enum + * - flags - struct fields or function parameters that are enums + * - Designate that this enum type E should be Flags in the generated C++ + * code + * - For example, if a struct field is defined as `[flags] ErrorFlag f;` + * (where ErrorFlag is defined as an enum elsewhere in mojom), then the + * generated code for this field will be `Flags f` * * Rules: * - If the type is defined in a libcamera C++ header *and* a (de)serializer is diff --git a/include/libcamera/ipa/ipa_interface.h b/include/libcamera/ipa/ipa_interface.h index 50ca0e7b..8afcfe21 100644 --- a/include/libcamera/ipa/ipa_interface.h +++ b/include/libcamera/ipa/ipa_interface.h @@ -13,6 +13,7 @@ #include #include +#include #include #include diff --git a/utils/ipc/generators/libcamera_templates/definition_functions.tmpl b/utils/ipc/generators/libcamera_templates/definition_functions.tmpl index 94bb4918..8b8509f3 100644 --- a/utils/ipc/generators/libcamera_templates/definition_functions.tmpl +++ b/utils/ipc/generators/libcamera_templates/definition_functions.tmpl @@ -9,7 +9,7 @@ # \param enum Enum object whose definition is to be generated #} {%- macro define_enum(enum) -%} -enum {{enum.mojom_name}} { +enum{{" class" if enum|is_scoped}} {{enum.mojom_name}} { {%- for field in enum.fields %} {{field.mojom_name}} = {{field.numeric_value}}, {%- endfor %} diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl b/utils/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl index 415ec283..160601f7 100644 --- a/utils/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl +++ b/utils/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl @@ -69,7 +69,7 @@ public: {%- for method in interface_event.methods %} Signal< {%- for param in method.parameters -%} - {{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod}} + {{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod and not param|is_enum}} {{- ", " if not loop.last}} {%- endfor -%} > {{method.mojom_name}}; diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl index c308dd10..ed270f5c 100644 --- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl +++ b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl @@ -46,7 +46,7 @@ public: {%- for method in interface_event.methods %} Signal< {%- for param in method.parameters -%} - {{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod}} + {{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod and not param|is_enum}} {{- ", " if not loop.last}} {%- endfor -%} > {{method.mojom_name}}; diff --git a/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl b/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl index cbcfb64a..2be65d43 100644 --- a/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl +++ b/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl @@ -62,7 +62,9 @@ {%- else %} std::tie({{param.mojom_name}}Buf, std::ignore) = {%- endif %} -{%- if param|is_enum %} +{%- if param|is_flags %} + IPADataSerializer<{{param|name_full}}>::serialize({{param.mojom_name}} +{%- elif param|is_enum %} IPADataSerializer::serialize(static_cast({{param.mojom_name}}) {%- else %} IPADataSerializer<{{param|name}}>::serialize({{param.mojom_name}} @@ -105,7 +107,9 @@ #} {%- macro deserialize_param(param, pointer, loop, buf, fds, iter, data_size) -%} {{"*" if pointer}}{{param.mojom_name}} = -{%- if param|is_enum %} +{%- if param|is_flags %} +IPADataSerializer<{{param|name_full}}>::deserialize( +{%- elif param|is_enum %} static_cast<{{param|name_full}}>(IPADataSerializer::deserialize( {%- else %} IPADataSerializer<{{param|name}}>::deserialize( @@ -133,7 +137,7 @@ IPADataSerializer<{{param|name}}>::deserialize( {%- if param|needs_control_serializer %} &controlSerializer_ {%- endif -%} -){{")" if param|is_enum}}; +){{")" if param|is_enum and not param|is_flags}}; {%- endmacro -%} diff --git a/utils/ipc/generators/libcamera_templates/serializer.tmpl b/utils/ipc/generators/libcamera_templates/serializer.tmpl index 77bae36f..323e1293 100644 --- a/utils/ipc/generators/libcamera_templates/serializer.tmpl +++ b/utils/ipc/generators/libcamera_templates/serializer.tmpl @@ -34,6 +34,10 @@ std::tie({{field.mojom_name}}, std::ignore) = {%- if field|is_pod %} IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}}); + {%- elif field|is_flags %} + IPADataSerializer<{{field|name_full}}>::serialize(data.{{field.mojom_name}}); + {%- elif field|is_enum_scoped %} + IPADataSerializer::serialize(static_cast(data.{{field.mojom_name}})); {%- elif field|is_enum %} IPADataSerializer::serialize(data.{{field.mojom_name}}); {%- endif %} @@ -96,6 +100,8 @@ {{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}} {%- if field|is_pod %} ret.{{field.mojom_name}} = IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field_size}}); + {%- elif field|is_flags %} + ret.{{field.mojom_name}} = IPADataSerializer<{{field|name_full}}>::deserialize(m, m + {{field_size}}); {%- else %} ret.{{field.mojom_name}} = static_cast<{{field|name_full}}>(IPADataSerializer::deserialize(m, m + {{field_size}})); {%- endif %} diff --git a/utils/ipc/generators/mojom_libcamera_generator.py b/utils/ipc/generators/mojom_libcamera_generator.py index 753bfc73..442f797c 100644 --- a/utils/ipc/generators/mojom_libcamera_generator.py +++ b/utils/ipc/generators/mojom_libcamera_generator.py @@ -74,6 +74,8 @@ def GetDefaultValue(element): return element.default if type(element.kind) == mojom.Kind: return '0' + if IsFlags(element): + return '' if mojom.IsEnumKind(element.kind): return f'static_cast<{element.kind.mojom_name}>(0)' if isinstance(element.kind, mojom.Struct) and \ @@ -184,7 +186,7 @@ def MethodParameters(method): params = [] for param in method.parameters: params.append('const %s %s%s' % (GetNameForElement(param), - '&' if not IsPod(param) else '', + '' if IsPod(param) or IsEnum(param) else '&', param.mojom_name)) for param in MethodParamOutputs(method): params.append(f'{GetNameForElement(param)} *{param.mojom_name}') @@ -220,9 +222,30 @@ def IsControls(element): def IsEnum(element): return mojom.IsEnumKind(element.kind) + +# Only works the enum definition, not types +def IsScoped(element): + attributes = getattr(element, 'attributes', None) + if not attributes: + return False + return 'scopedEnum' in attributes + + +def IsEnumScoped(element): + if not IsEnum(element): + return False + return IsScoped(element.kind) + def IsFd(element): return mojom.IsStructKind(element.kind) and element.kind.mojom_name == "SharedFD" + +def IsFlags(element): + attributes = getattr(element, 'attributes', None) + if not attributes: + return False + return 'flags' in attributes + def IsMap(element): return mojom.IsMapKind(element.kind) @@ -251,9 +274,11 @@ def ByteWidthFromCppType(t): raise Exception('invalid type') return str(int(_bit_widths[key]) // 8) - # Get the type name for a given element def GetNameForElement(element): + # Flags + if IsFlags(element): + return f'Flags<{GetFullNameForElement(element.kind)}>' # structs if (mojom.IsEnumKind(element) or mojom.IsInterfaceKind(element) or @@ -302,15 +327,18 @@ def GetNameForElement(element): def GetFullNameForElement(element): name = GetNameForElement(element) namespace_str = '' - if mojom.IsStructKind(element): + if (mojom.IsStructKind(element) or mojom.IsEnumKind(element)): namespace_str = element.module.mojom_namespace.replace('.', '::') elif (hasattr(element, 'kind') and - (mojom.IsStructKind(element.kind) or - mojom.IsEnumKind(element.kind))): + (mojom.IsStructKind(element.kind) or mojom.IsEnumKind(element.kind))): namespace_str = element.kind.module.mojom_namespace.replace('.', '::') if namespace_str == '': return name + + if IsFlags(element): + return GetNameForElement(element) + return f'{namespace_str}::{name}' def ValidateZeroLength(l, s, cap=True): @@ -407,10 +435,13 @@ class Generator(generator.Generator): 'is_array': IsArray, 'is_controls': IsControls, 'is_enum': IsEnum, + 'is_enum_scoped': IsEnumScoped, 'is_fd': IsFd, + 'is_flags': IsFlags, 'is_map': IsMap, 'is_plain_struct': IsPlainStruct, 'is_pod': IsPod, + 'is_scoped': IsScoped, 'is_str': IsStr, 'method_input_has_fd': MethodInputHasFd, 'method_output_has_fd': MethodOutputHasFd, -- cgit v1.2.1