From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: "Xavier Roumegue (OSS)" <xavier.roumegue@oss.nxp.com>
Cc: Umang Jain <umang.jain@ideasonboard.com>,
linux-media@vger.kernel.org,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Sakari Ailus <sakari.ailus@linux.intel.com>,
Stefan Klug <stefan.klug@ideasonboard.com>,
Kieran Bingham <kieran.bingham@ideasonboard.com>
Subject: Re: [PATCH] media: dw100: Enable dynamic vertex map
Date: Sun, 27 Oct 2024 16:40:40 +0200 [thread overview]
Message-ID: <20241027144040.GI6519@pendragon.ideasonboard.com> (raw)
In-Reply-To: <a73be13d-a2ed-48cd-a84e-805fb379dc09@oss.nxp.com>
On Sat, Oct 26, 2024 at 09:52:43PM +0200, Xavier Roumegue wrote:
> Hi Umang,
>
> Thanks for the patch, this feature sounds promising.
>
> On 10/22/24 8:31 AM, Umang Jain wrote:
> > Currently, vertex maps cannot be updated dynamically while dw100
> > is streaming. This patch enables the support to update the vertex
> > map dynamically at runtime.
> >
> > To support this functionality, we need to allocate and track two
> > sets of DMA-allocated vertex maps, one for the currently applied map
> > and another for the updated (pending) map. Before the start of next
> > frame, if a new user-supplied vertex map is available, the hardware
> > mapping is changed to use new vertex map, thus enabling the user to
> > update the vertex map at runtime.
How do you synchronize the new map with the jobs ? That doesn't seem to
be supported by the patch, is it a feature that you don't need ?
> >
> > We should ensure no race occurs when the vertex map is updated multiple
> > times when a frame is processing. Hence, vertex map is never updated to
> > the applied vertex map index in .s_ctrl(). It is always updated on the
> > pending vertex map slot, with `maps_mutex` lock held. `maps_mutex` lock
> > is also held when the pending vertex map is applied to the hardware in
> > dw100_start().
> >
> > Ability to update the vertex map at runtime, enables abritrary rotation
s/abritrary/arbitrary/
> > and digital zoom features for the input frames, through the dw100
> > hardware.
> >
> > Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
> > ---
> > drivers/media/platform/nxp/dw100/dw100.c | 73 ++++++++++++++++++------
> > 1 file changed, 56 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c
> > index 54ebf59df682..42712ccff754 100644
> > --- a/drivers/media/platform/nxp/dw100/dw100.c
> > +++ b/drivers/media/platform/nxp/dw100/dw100.c
> > @@ -83,6 +83,11 @@ struct dw100_q_data {
> > struct v4l2_rect crop;
> > };
> >
> > +struct dw100_map {
> > + unsigned int *map;
> > + dma_addr_t map_dma;
I would have called the field just 'dma' as it's already qualified by
the structure name or the field name in dw100_ctx.
> > +};
> > +
> > struct dw100_ctx {
> > struct v4l2_fh fh;
> > struct dw100_device *dw_dev;
> > @@ -92,12 +97,14 @@ struct dw100_ctx {
> > struct mutex vq_mutex;
> >
> > /* Look Up Table for pixel remapping */
> > - unsigned int *map;
> > - dma_addr_t map_dma;
> > + struct dw100_map maps[2];
> > + unsigned int applied_map_id;
> > size_t map_size;
> > unsigned int map_width;
> > unsigned int map_height;
> > bool user_map_is_set;
> > + bool user_map_is_updated;
> > + struct mutex maps_mutex;
> >
> > /* Source and destination queue data */
> > struct dw100_q_data q_data[2];
> > @@ -308,24 +315,31 @@ static int dw100_create_mapping(struct dw100_ctx *ctx)
> > {
> > u32 *user_map;
> >
> > - if (ctx->map)
> > - dma_free_coherent(&ctx->dw_dev->pdev->dev, ctx->map_size,
> > - ctx->map, ctx->map_dma);
> > + for (unsigned int i = 0; i < 2; i++) {
for (unsigned int i = 0; i < ARRAY_SIZE(ctx->maps); i++) {
struct dw100_map *map = &ctx->maps[i];
and use map below.
> > + if (ctx->maps[i].map)
> > + dma_free_coherent(&ctx->dw_dev->pdev->dev, ctx->map_size,
> > + ctx->maps[i].map, ctx->maps[i].map_dma);
> >
> > - ctx->map = dma_alloc_coherent(&ctx->dw_dev->pdev->dev, ctx->map_size,
> > - &ctx->map_dma, GFP_KERNEL);
> > + ctx->maps[i].map = dma_alloc_coherent(&ctx->dw_dev->pdev->dev, ctx->map_size,
> > + &ctx->maps[i].map_dma, GFP_KERNEL);
> >
> > - if (!ctx->map)
> > - return -ENOMEM;
> > + if (!ctx->maps[i].map)
> > + return -ENOMEM;
> > + }
> >
> > user_map = dw100_get_user_map(ctx);
> > - memcpy(ctx->map, user_map, ctx->map_size);
> > +
> > + mutex_lock(&ctx->maps_mutex);
> > + ctx->applied_map_id = 0;
> > + memcpy(ctx->maps[ctx->applied_map_id].map, user_map, ctx->map_size);
> > + mutex_unlock(&ctx->maps_mutex);
> >
> > dev_dbg(&ctx->dw_dev->pdev->dev,
> > "%ux%u %s mapping created (d:%pad-c:%p) for stream %ux%u->%ux%u\n",
> > ctx->map_width, ctx->map_height,
> > ctx->user_map_is_set ? "user" : "identity",
> > - &ctx->map_dma, ctx->map,
> > + &ctx->maps[ctx->applied_map_id].map_dma,
> > + ctx->maps[ctx->applied_map_id].map,
> > ctx->q_data[DW100_QUEUE_SRC].pix_fmt.width,
> > ctx->q_data[DW100_QUEUE_DST].pix_fmt.height,
> > ctx->q_data[DW100_QUEUE_SRC].pix_fmt.width,
> > @@ -336,10 +350,12 @@ static int dw100_create_mapping(struct dw100_ctx *ctx)
> >
> > static void dw100_destroy_mapping(struct dw100_ctx *ctx)
> > {
> > - if (ctx->map) {
> > - dma_free_coherent(&ctx->dw_dev->pdev->dev, ctx->map_size,
> > - ctx->map, ctx->map_dma);
> > - ctx->map = NULL;
> > + for (unsigned int i = 0; i < 2; i++) {
for (unsigned int i = 0; i < ARRAY_SIZE(ctx->maps); i++) {
struct dw100_map *map = &ctx->maps[i];
and use map below.
> > + if (ctx->maps[i].map)
> > + dma_free_coherent(&ctx->dw_dev->pdev->dev, ctx->map_size,
> > + ctx->maps[i].map, ctx->maps[i].map_dma);
> > +
> > + ctx->maps[i].map = NULL;
> > }
> > }
> >
> > @@ -350,6 +366,15 @@ static int dw100_s_ctrl(struct v4l2_ctrl *ctrl)
> >
> > switch (ctrl->id) {
> > case V4L2_CID_DW100_DEWARPING_16x16_VERTEX_MAP:
> > + u32 *user_map = ctrl->p_new.p_u32;
>
> A warning to fix here.
>
> > + unsigned int id;
> > +
> > + mutex_lock(&ctx->maps_mutex);
> > + id = ctx->applied_map_id ? 0 : 1;
> > + memcpy(ctx->maps[id].map, user_map, ctx->map_size);
> > + ctx->user_map_is_updated = true;
>
> If you call the control before to start the stream, the dma mapping is
> not yet done(dw100_create_mapping not yet called). Hence, copying the
> user map to a NULL pointer.
The maps could be allocated in dw100_open() when creating the context.
That would likely require moving the initialization of ctx->map_width,
ctx->map_height and ctx->map_size as well. The handling of the identity
map would probably need to be rewritten too.
> > + mutex_unlock(&ctx->maps_mutex);
> > +
> > ctx->user_map_is_set = true;
> > break;
> > }
> > @@ -655,6 +680,8 @@ static int dw100_open(struct file *file)
> >
> > v4l2_fh_add(&ctx->fh);
> >
> > + mutex_init(&ctx->maps_mutex);
> > +
> > return 0;
> >
> > err:
> > @@ -675,6 +702,7 @@ static int dw100_release(struct file *file)
> > v4l2_ctrl_handler_free(&ctx->hdl);
> > v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
> > mutex_destroy(&ctx->vq_mutex);
> > + mutex_destroy(&ctx->maps_mutex);
> > kfree(ctx);
> >
> > return 0;
> > @@ -1453,8 +1481,19 @@ static void dw100_start(struct dw100_ctx *ctx, struct vb2_v4l2_buffer *in_vb,
> > dw100_hw_set_destination(dw_dev, &ctx->q_data[DW100_QUEUE_DST],
> > ctx->q_data[DW100_QUEUE_SRC].fmt,
> > &out_vb->vb2_buf);
> > - dw100_hw_set_mapping(dw_dev, ctx->map_dma,
> > - ctx->map_width, ctx->map_height);
> > +
> > +
> > + mutex_lock(&ctx->maps_mutex);
> > + if (ctx->user_map_is_updated) {
>
> The hardware register must unconditionally be updated while starting a
> new context, as a v4l2 m2m supports multi context operations. Otherwise,
> you may be running with the user mapping used by the previous context.
>
> Moreover, the hardware mapping will not be set in case you use the
> driver as a simple scaler without user mapping, which causes the process
> to hang as the run does not start and never completes.
>
> > + unsigned int id = ctx->applied_map_id ? 0 : 1;
> > +
> > + dw100_hw_set_mapping(dw_dev, ctx->maps[id].map_dma,
> > + ctx->map_width, ctx->map_height);
> > + ctx->applied_map_id = id;
> > + ctx->user_map_is_updated = false;
> > + }
> > + mutex_unlock(&ctx->maps_mutex);
> > +
> > dw100_hw_enable_irq(dw_dev);
> > dw100_hw_dewarp_start(dw_dev);
> >
>
> It sounds as this patch requires a collaborative application for running
> well. All my simple tests failed.
>
> You can test a simple scaler/pixfmt conversion operation with v4l2 utils:
>
>
> v4l2-ctl \
> -d 0 \
> --set-fmt-video-out width=640,height=480,pixelformat=NV12,field=none \
> --set-fmt-video width=640,height=480,pixelformat=NV21,field=none \
> --stream-out-pattern 3 \
> --set-selection-output\
> target=crop,top=0,left=0,width=640,height=480,flags= \
> --stream-count 100 \
> --stream-mmap \
> --stream-out-mmap
--
Regards,
Laurent Pinchart
next prev parent reply other threads:[~2024-10-27 14:40 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-22 6:31 [PATCH] media: dw100: Enable dynamic vertex map Umang Jain
2024-10-22 23:09 ` kernel test robot
2024-10-26 19:52 ` Xavier Roumegue (OSS)
2024-10-27 14:40 ` Laurent Pinchart [this message]
2024-10-28 7:27 ` Umang Jain
2024-10-28 14:32 ` Laurent Pinchart
2024-10-28 14:58 ` Umang Jain
2024-10-28 14:17 ` Umang Jain
2024-10-28 14:41 ` Laurent Pinchart
2024-10-28 15:02 ` Umang Jain
2024-10-28 16:38 ` Laurent Pinchart
2024-10-28 7:32 ` Umang Jain
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241027144040.GI6519@pendragon.ideasonboard.com \
--to=laurent.pinchart@ideasonboard.com \
--cc=kieran.bingham@ideasonboard.com \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=sakari.ailus@linux.intel.com \
--cc=stefan.klug@ideasonboard.com \
--cc=umang.jain@ideasonboard.com \
--cc=xavier.roumegue@oss.nxp.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox