[libcamera-devel,v4,1/4] libcamera: V4L2Device: Remove the controls order assumption in updateControls()
diff mbox series

Message ID 20210422021809.520675-2-hiroh@chromium.org
State Superseded
Headers show
Series
  • Clean up V4L2Device code
Related show

Commit Message

Hirokazu Honda April 22, 2021, 2:18 a.m. UTC
The original updateControls() has the assumption that ctrls and
v4l2Ctrls lists in the same order. It is dependent on the caller
implementation though. This changes updateControls()
implementation so that it works without the assumption.

Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
---
 src/libcamera/v4l2_device.cpp | 32 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

Comments

Jacopo Mondi April 22, 2021, 7:29 a.m. UTC | #1
Hi Hiro,

On Thu, Apr 22, 2021 at 11:18:06AM +0900, Hirokazu Honda wrote:
> The original updateControls() has the assumption that ctrls and
> v4l2Ctrls lists in the same order. It is dependent on the caller

s/in the same order/are in the same order/

> implementation though. This changes updateControls()
> implementation so that it works without the assumption.
>
> Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
> ---
>  src/libcamera/v4l2_device.cpp | 32 +++++++++++++-------------------
>  1 file changed, 13 insertions(+), 19 deletions(-)
>
> diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp
> index decd19ef..3c32d682 100644
> --- a/src/libcamera/v4l2_device.cpp
> +++ b/src/libcamera/v4l2_device.cpp
> @@ -179,12 +179,6 @@ ControlList V4L2Device::getControls(const std::vector<uint32_t> &ids)
>
>  	ControlList ctrls{ controls_ };
>
> -	/*
> -	 * Start by filling the ControlList. This can't be combined with filling
> -	 * v4l2Ctrls, as updateControls() relies on both containers having the
> -	 * same order, and the control list is based on a map, which is not
> -	 * sorted by insertion order.
> -	 */
>  	for (uint32_t id : ids) {
>  		const auto iter = controls_.find(id);
>  		if (iter == controls_.end()) {
> @@ -525,19 +519,19 @@ void V4L2Device::updateControls(ControlList *ctrls,
>  				const struct v4l2_ext_control *v4l2Ctrls,
>  				unsigned int count)
>  {
> -	unsigned int i = 0;
> -	for (auto &ctrl : *ctrls) {
> -		if (i == count)
> -			break;
> -
> -		const struct v4l2_ext_control *v4l2Ctrl = &v4l2Ctrls[i];
> -		unsigned int id = ctrl.first;
> -		ControlValue &value = ctrl.second;
> +	for (unsigned int i = 0; i < count; i++) {
> +		const struct v4l2_ext_control &v4l2Ctrl = v4l2Ctrls[i];
> +		const unsigned int id = v4l2Ctrl.id;
> +		if (!ctrls->contains(id)) {
> +			LOG(V4L2, Error) << "ControlList doesn't contain id: "
> +					 << id;
> +			return;
> +		}

Can this happen ?

>
> -		const auto iter = controls_.find(id);
> -		switch (iter->first->type()) {
> +		ControlValue value = ctrls->get(id);

This should be &value (or better *value, if you want to modify it) ? see [1]

> +		switch (value.type()) {

The type information recorded in controls_ (which is a
ControlInfoMap) and in the ControlValue should be the same, hence
there should be no functional changes, right ?

>  		case ControlTypeInteger64:
> -			value.set<int64_t>(v4l2Ctrl->value64);
> +			value.set<int64_t>(v4l2Ctrl.value64);
>  			break;
>
>  		case ControlTypeByte:
> @@ -552,11 +546,11 @@ void V4L2Device::updateControls(ControlList *ctrls,
>  			 * \todo To be changed when support for string controls
>  			 * will be added.
>  			 */
> -			value.set<int32_t>(v4l2Ctrl->value);
> +			value.set<int32_t>(v4l2Ctrl.value);
>  			break;
>  		}
>
> -		i++;
> +		ctrls->set(id, value);

[1] so you can avoid this ?

I still think we pay a little performance loss, for the additional
crls->get() but the code is nicer to ead indeed

Can you specify you've run all tests and they're all good in the cover
letter of the next iteration for out peace of mind ? :)

Thanks
   j
>  	}
>  }
>
> --
> 2.31.1.368.gbe11c130af-goog
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
Hirokazu Honda April 22, 2021, 7:40 a.m. UTC | #2
On Thu, Apr 22, 2021 at 4:29 PM Jacopo Mondi <jacopo@jmondi.org> wrote:
>
> Hi Hiro,
>
> On Thu, Apr 22, 2021 at 11:18:06AM +0900, Hirokazu Honda wrote:
> > The original updateControls() has the assumption that ctrls and
> > v4l2Ctrls lists in the same order. It is dependent on the caller
>
> s/in the same order/are in the same order/
>
> > implementation though. This changes updateControls()
> > implementation so that it works without the assumption.
> >
> > Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
> > ---
> >  src/libcamera/v4l2_device.cpp | 32 +++++++++++++-------------------
> >  1 file changed, 13 insertions(+), 19 deletions(-)
> >
> > diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp
> > index decd19ef..3c32d682 100644
> > --- a/src/libcamera/v4l2_device.cpp
> > +++ b/src/libcamera/v4l2_device.cpp
> > @@ -179,12 +179,6 @@ ControlList V4L2Device::getControls(const std::vector<uint32_t> &ids)
> >
> >       ControlList ctrls{ controls_ };
> >
> > -     /*
> > -      * Start by filling the ControlList. This can't be combined with filling
> > -      * v4l2Ctrls, as updateControls() relies on both containers having the
> > -      * same order, and the control list is based on a map, which is not
> > -      * sorted by insertion order.
> > -      */
> >       for (uint32_t id : ids) {
> >               const auto iter = controls_.find(id);
> >               if (iter == controls_.end()) {
> > @@ -525,19 +519,19 @@ void V4L2Device::updateControls(ControlList *ctrls,
> >                               const struct v4l2_ext_control *v4l2Ctrls,
> >                               unsigned int count)
> >  {
> > -     unsigned int i = 0;
> > -     for (auto &ctrl : *ctrls) {
> > -             if (i == count)
> > -                     break;
> > -
> > -             const struct v4l2_ext_control *v4l2Ctrl = &v4l2Ctrls[i];
> > -             unsigned int id = ctrl.first;
> > -             ControlValue &value = ctrl.second;
> > +     for (unsigned int i = 0; i < count; i++) {
> > +             const struct v4l2_ext_control &v4l2Ctrl = v4l2Ctrls[i];
> > +             const unsigned int id = v4l2Ctrl.id;
> > +             if (!ctrls->contains(id)) {
> > +                     LOG(V4L2, Error) << "ControlList doesn't contain id: "
> > +                                      << id;
> > +                     return;
> > +             }
>
> Can this happen ?
>

Nope, I will delete it in the next patch series.

> >
> > -             const auto iter = controls_.find(id);
> > -             switch (iter->first->type()) {
> > +             ControlValue value = ctrls->get(id);
>
> This should be &value (or better *value, if you want to modify it) ? see [1]
>
> > +             switch (value.type()) {
>
> The type information recorded in controls_ (which is a
> ControlInfoMap) and in the ControlValue should be the same, hence
> there should be no functional changes, right ?
>

Yes, I understand so.

> >               case ControlTypeInteger64:
> > -                     value.set<int64_t>(v4l2Ctrl->value64);
> > +                     value.set<int64_t>(v4l2Ctrl.value64);
> >                       break;
> >
> >               case ControlTypeByte:
> > @@ -552,11 +546,11 @@ void V4L2Device::updateControls(ControlList *ctrls,
> >                        * \todo To be changed when support for string controls
> >                        * will be added.
> >                        */
> > -                     value.set<int32_t>(v4l2Ctrl->value);
> > +                     value.set<int32_t>(v4l2Ctrl.value);
> >                       break;
> >               }
> >
> > -             i++;
> > +             ctrls->set(id, value);
>
> [1] so you can avoid this ?
>
> I still think we pay a little performance loss, for the additional
> crls->get() but the code is nicer to ead indeed
>

Surprisingly, ControlList doesn't allow getting a mutable reference
while they allow a mutable iterator through begin()-end().
I would add ControlList::get(id) that returns a mutable reference or
pointer, if we all agree.


> Can you specify you've run all tests and they're all good in the cover
> letter of the next iteration for out peace of mind ? :)
>

Sure. Now I am working for a way of running the test on test chromebook device.

-Hiro
> Thanks
>    j
> >       }
> >  }
> >
> > --
> > 2.31.1.368.gbe11c130af-goog
> >
> > _______________________________________________
> > libcamera-devel mailing list
> > libcamera-devel@lists.libcamera.org
> > https://lists.libcamera.org/listinfo/libcamera-devel
Laurent Pinchart April 23, 2021, 2:53 a.m. UTC | #3
Hi Hiro,

Thank you for the patch.

On Thu, Apr 22, 2021 at 04:40:44PM +0900, Hirokazu Honda wrote:
> On Thu, Apr 22, 2021 at 4:29 PM Jacopo Mondi wrote:
> > On Thu, Apr 22, 2021 at 11:18:06AM +0900, Hirokazu Honda wrote:
> > > The original updateControls() has the assumption that ctrls and
> > > v4l2Ctrls lists in the same order. It is dependent on the caller
> >
> > s/in the same order/are in the same order/
> >
> > > implementation though. This changes updateControls()
> > > implementation so that it works without the assumption.
> > >
> > > Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
> > > ---
> > >  src/libcamera/v4l2_device.cpp | 32 +++++++++++++-------------------
> > >  1 file changed, 13 insertions(+), 19 deletions(-)
> > >
> > > diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp
> > > index decd19ef..3c32d682 100644
> > > --- a/src/libcamera/v4l2_device.cpp
> > > +++ b/src/libcamera/v4l2_device.cpp
> > > @@ -179,12 +179,6 @@ ControlList V4L2Device::getControls(const std::vector<uint32_t> &ids)
> > >
> > >       ControlList ctrls{ controls_ };
> > >
> > > -     /*
> > > -      * Start by filling the ControlList. This can't be combined with filling
> > > -      * v4l2Ctrls, as updateControls() relies on both containers having the
> > > -      * same order, and the control list is based on a map, which is not
> > > -      * sorted by insertion order.
> > > -      */

Now that this limitation is removed, should we also combine the
generation of ctrls and v4l2Ctrls in the same loop ?

> > >       for (uint32_t id : ids) {
> > >               const auto iter = controls_.find(id);
> > >               if (iter == controls_.end()) {
> > > @@ -525,19 +519,19 @@ void V4L2Device::updateControls(ControlList *ctrls,
> > >                               const struct v4l2_ext_control *v4l2Ctrls,
> > >                               unsigned int count)
> > >  {
> > > -     unsigned int i = 0;
> > > -     for (auto &ctrl : *ctrls) {
> > > -             if (i == count)
> > > -                     break;
> > > -
> > > -             const struct v4l2_ext_control *v4l2Ctrl = &v4l2Ctrls[i];
> > > -             unsigned int id = ctrl.first;
> > > -             ControlValue &value = ctrl.second;
> > > +     for (unsigned int i = 0; i < count; i++) {
> > > +             const struct v4l2_ext_control &v4l2Ctrl = v4l2Ctrls[i];
> > > +             const unsigned int id = v4l2Ctrl.id;
> > > +             if (!ctrls->contains(id)) {
> > > +                     LOG(V4L2, Error) << "ControlList doesn't contain id: "
> > > +                                      << id;
> > > +                     return;
> > > +             }
> >
> > Can this happen ?
> 
> Nope, I will delete it in the next patch series.
> 
> > >
> > > -             const auto iter = controls_.find(id);
> > > -             switch (iter->first->type()) {
> > > +             ControlValue value = ctrls->get(id);
> >
> > This should be &value (or better *value, if you want to modify it) ? see [1]
> >
> > > +             switch (value.type()) {
> >
> > The type information recorded in controls_ (which is a
> > ControlInfoMap) and in the ControlValue should be the same, hence
> > there should be no functional changes, right ?
> 
> Yes, I understand so.
> 
> > >               case ControlTypeInteger64:
> > > -                     value.set<int64_t>(v4l2Ctrl->value64);
> > > +                     value.set<int64_t>(v4l2Ctrl.value64);
> > >                       break;
> > >
> > >               case ControlTypeByte:
> > > @@ -552,11 +546,11 @@ void V4L2Device::updateControls(ControlList *ctrls,
> > >                        * \todo To be changed when support for string controls
> > >                        * will be added.
> > >                        */
> > > -                     value.set<int32_t>(v4l2Ctrl->value);
> > > +                     value.set<int32_t>(v4l2Ctrl.value);
> > >                       break;
> > >               }
> > >
> > > -             i++;
> > > +             ctrls->set(id, value);
> >
> > [1] so you can avoid this ?
> >
> > I still think we pay a little performance loss, for the additional
> > crls->get() but the code is nicer to ead indeed
> 
> Surprisingly, ControlList doesn't allow getting a mutable reference
> while they allow a mutable iterator through begin()-end().
> I would add ControlList::get(id) that returns a mutable reference or
> pointer, if we all agree.

Good question. I think the reason why there's no mutable accessor (a
non-const version of ControlList::get()) was that it was envisioned that
setting a control value would perform sanity checks (for instance
checking the value against the minimum/maximum). Accessing the
underlying storage directly wouldn't allow us to do so. This is not
implemented, and the iterators allow us to bypass that, so we could as
well be consistent. I'm just a bit worried that making use of mutable
access through the code base will make it more difficult to add checks
later. Given that the code in this function only deals with single u32
and u64 values, the impact of a copy is probably negligible.

> > Can you specify you've run all tests and they're all good in the cover
> > letter of the next iteration for out peace of mind ? :)
> 
> Sure. Now I am working for a way of running the test on test chromebook device.
> 
> > >       }
> > >  }

Patch
diff mbox series

diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp
index decd19ef..3c32d682 100644
--- a/src/libcamera/v4l2_device.cpp
+++ b/src/libcamera/v4l2_device.cpp
@@ -179,12 +179,6 @@  ControlList V4L2Device::getControls(const std::vector<uint32_t> &ids)
 
 	ControlList ctrls{ controls_ };
 
-	/*
-	 * Start by filling the ControlList. This can't be combined with filling
-	 * v4l2Ctrls, as updateControls() relies on both containers having the
-	 * same order, and the control list is based on a map, which is not
-	 * sorted by insertion order.
-	 */
 	for (uint32_t id : ids) {
 		const auto iter = controls_.find(id);
 		if (iter == controls_.end()) {
@@ -525,19 +519,19 @@  void V4L2Device::updateControls(ControlList *ctrls,
 				const struct v4l2_ext_control *v4l2Ctrls,
 				unsigned int count)
 {
-	unsigned int i = 0;
-	for (auto &ctrl : *ctrls) {
-		if (i == count)
-			break;
-
-		const struct v4l2_ext_control *v4l2Ctrl = &v4l2Ctrls[i];
-		unsigned int id = ctrl.first;
-		ControlValue &value = ctrl.second;
+	for (unsigned int i = 0; i < count; i++) {
+		const struct v4l2_ext_control &v4l2Ctrl = v4l2Ctrls[i];
+		const unsigned int id = v4l2Ctrl.id;
+		if (!ctrls->contains(id)) {
+			LOG(V4L2, Error) << "ControlList doesn't contain id: "
+					 << id;
+			return;
+		}
 
-		const auto iter = controls_.find(id);
-		switch (iter->first->type()) {
+		ControlValue value = ctrls->get(id);
+		switch (value.type()) {
 		case ControlTypeInteger64:
-			value.set<int64_t>(v4l2Ctrl->value64);
+			value.set<int64_t>(v4l2Ctrl.value64);
 			break;
 
 		case ControlTypeByte:
@@ -552,11 +546,11 @@  void V4L2Device::updateControls(ControlList *ctrls,
 			 * \todo To be changed when support for string controls
 			 * will be added.
 			 */
-			value.set<int32_t>(v4l2Ctrl->value);
+			value.set<int32_t>(v4l2Ctrl.value);
 			break;
 		}
 
-		i++;
+		ctrls->set(id, value);
 	}
 }