diff mbox series

[v3,1/2] v4l2-compliance: Test queue maximum buffers allocation

Message ID 20231002120813.119791-1-benjamin.gaignard@collabora.com
State New
Headers show
Series [v3,1/2] v4l2-compliance: Test queue maximum buffers allocation | expand

Commit Message

Benjamin Gaignard Oct. 2, 2023, 12:08 p.m. UTC
If V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS is set v4l2_create_buffers
max_buffers field reports the maximum number of buffers supported
by the queue.
Add a test to allocate this maximum value and make sure that one
more allocation is failing.
Display the flag in v4l2-ctl.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
---
version 3:
- change test fail check because vim2m do not allocate all the
  requested buffers (memory size limitation)
 include/linux/videodev2.h                   |  7 +++-
 utils/common/cv4l-helpers.h                 |  1 +
 utils/common/v4l-helpers.h                  |  5 +++
 utils/common/v4l2-info.cpp                  |  1 +
 utils/v4l2-compliance/v4l2-compliance.cpp   |  1 +
 utils/v4l2-compliance/v4l2-compliance.h     |  1 +
 utils/v4l2-compliance/v4l2-test-buffers.cpp | 42 ++++++++++++++++++++-
 7 files changed, 56 insertions(+), 2 deletions(-)

Comments

Hans Verkuil Oct. 27, 2023, 8:10 a.m. UTC | #1
On 02/10/2023 14:08, Benjamin Gaignard wrote:
> If V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS is set v4l2_create_buffers

Can you post a v4? This CAP name changed, so this is out of date.

Also, please put the videodev2.h change in a separate patch: that one
won't be merged since when this is merged we'll sync v4l-utils with
the latest kernel headers.

So this videodev2.h change is just for testing this.

Regards,

	Hans

> max_buffers field reports the maximum number of buffers supported
> by the queue.
> Add a test to allocate this maximum value and make sure that one
> more allocation is failing.
> Display the flag in v4l2-ctl.>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
> ---
> version 3:
> - change test fail check because vim2m do not allocate all the
>   requested buffers (memory size limitation)
>  include/linux/videodev2.h                   |  7 +++-
>  utils/common/cv4l-helpers.h                 |  1 +
>  utils/common/v4l-helpers.h                  |  5 +++
>  utils/common/v4l2-info.cpp                  |  1 +
>  utils/v4l2-compliance/v4l2-compliance.cpp   |  1 +
>  utils/v4l2-compliance/v4l2-compliance.h     |  1 +
>  utils/v4l2-compliance/v4l2-test-buffers.cpp | 42 ++++++++++++++++++++-
>  7 files changed, 56 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> index c19441a1..ac5d2980 100644
> --- a/include/linux/videodev2.h
> +++ b/include/linux/videodev2.h
> @@ -986,6 +986,7 @@ struct v4l2_requestbuffers {
>  #define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS		(1 << 4)
>  #define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF	(1 << 5)
>  #define V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS		(1 << 6)
> +#define V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS		(1 << 7)
>  
>  /**
>   * struct v4l2_plane - plane info for multi-planar buffers
> @@ -2531,6 +2532,9 @@ struct v4l2_dbg_chip_info {
>   * @flags:	additional buffer management attributes (ignored unless the
>   *		queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability
>   *		and configured for MMAP streaming I/O).
> + * @max_buffers: if V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS capability flag is set
> + *		 this field indicate the maximum possible number of buffers
> + *		 for this queue.
>   * @reserved:	future extensions
>   */
>  struct v4l2_create_buffers {
> @@ -2540,7 +2544,8 @@ struct v4l2_create_buffers {
>  	struct v4l2_format	format;
>  	__u32			capabilities;
>  	__u32			flags;
> -	__u32			reserved[6];
> +	__u32			max_buffers;
> +	__u32			reserved[5];
>  };
>  
>  /*
> diff --git a/utils/common/cv4l-helpers.h b/utils/common/cv4l-helpers.h
> index 91a04146..5a515a13 100644
> --- a/utils/common/cv4l-helpers.h
> +++ b/utils/common/cv4l-helpers.h
> @@ -743,6 +743,7 @@ public:
>  	unsigned g_type() const { return v4l_queue_g_type(this); }
>  	unsigned g_memory() const { return v4l_queue_g_memory(this); }
>  	unsigned g_buffers() const { return v4l_queue_g_buffers(this); }
> +	unsigned g_max_buffers() const { return v4l_queue_g_max_buffers(this); }
>  	unsigned g_num_planes() const { return v4l_queue_g_num_planes(this); }
>  	unsigned g_capabilities() const { return v4l_queue_g_capabilities(this); }
>  	unsigned g_length(unsigned plane) const { return v4l_queue_g_length(this, plane); }
> diff --git a/utils/common/v4l-helpers.h b/utils/common/v4l-helpers.h
> index f8e96d58..5853f753 100644
> --- a/utils/common/v4l-helpers.h
> +++ b/utils/common/v4l-helpers.h
> @@ -1429,6 +1429,7 @@ struct v4l_queue {
>  	unsigned mappings;
>  	unsigned num_planes;
>  	unsigned capabilities;
> +	unsigned max_buffers;
>  
>  	__u32 lengths[VIDEO_MAX_PLANES];
>  	__u32 mem_offsets[VIDEO_MAX_FRAME][VIDEO_MAX_PLANES];
> @@ -1453,6 +1454,7 @@ static inline void v4l_queue_init(struct v4l_queue *q,
>  static inline unsigned v4l_queue_g_type(const struct v4l_queue *q) { return q->type; }
>  static inline unsigned v4l_queue_g_memory(const struct v4l_queue *q) { return q->memory; }
>  static inline unsigned v4l_queue_g_buffers(const struct v4l_queue *q) { return q->buffers; }
> +static inline unsigned v4l_queue_g_max_buffers(const struct v4l_queue *q) { return q->max_buffers; }
>  static inline unsigned v4l_queue_g_mappings(const struct v4l_queue *q) { return q->mappings; }
>  static inline unsigned v4l_queue_g_num_planes(const struct v4l_queue *q) { return q->num_planes; }
>  static inline unsigned v4l_queue_g_capabilities(const struct v4l_queue *q) { return q->capabilities; }
> @@ -1587,6 +1589,9 @@ static inline int v4l_queue_create_bufs(struct v4l_fd *f,
>  	if (ret)
>  		return ret;
>  	q->capabilities = createbufs.capabilities;
> +	q->max_buffers = 32;
> +	if (q->capabilities & V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS)
> +		q->max_buffers = createbufs.max_buffers;
>  	q->buffers += createbufs.count;
>  	return v4l_queue_querybufs(f, q, q->buffers - createbufs.count);
>  }
> diff --git a/utils/common/v4l2-info.cpp b/utils/common/v4l2-info.cpp
> index 4f8c2aa7..7adfedfc 100644
> --- a/utils/common/v4l2-info.cpp
> +++ b/utils/common/v4l2-info.cpp
> @@ -206,6 +206,7 @@ static constexpr flag_def bufcap_def[] = {
>  	{ V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS, "orphaned-bufs" },
>  	{ V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF, "m2m-hold-capture-buf" },
>  	{ V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS, "mmap-cache-hints" },
> +	{ V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS, "set-max-bufs" },
>  	{ 0, nullptr }
>  };
>  
> diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp
> index f62016e5..56190448 100644
> --- a/utils/v4l2-compliance/v4l2-compliance.cpp
> +++ b/utils/v4l2-compliance/v4l2-compliance.cpp
> @@ -1448,6 +1448,7 @@ void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_
>  
>  		printf("Buffer ioctls%s:\n", suffix);
>  		printf("\ttest VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: %s\n", ok(testReqBufs(&node)));
> +		printf("\ttest CREATE_BUFS maximum buffers: %s\n", ok(testCreateBufsMax(&node)));
>  		// Reopen after each streaming test to reset the streaming state
>  		// in case of any errors in the preceeding test.
>  		node.reopen();
> diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h
> index 7caf254b..4886e4c8 100644
> --- a/utils/v4l2-compliance/v4l2-compliance.h
> +++ b/utils/v4l2-compliance/v4l2-compliance.h
> @@ -383,6 +383,7 @@ int testReqBufs(struct node *node);
>  int testReadWrite(struct node *node);
>  int testExpBuf(struct node *node);
>  int testBlockingWait(struct node *node);
> +int testCreateBufsMax(struct node *node);
>  
>  // 32-bit architecture, 32/64-bit time_t tests
>  int testTime32_64(struct node *node);
> diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp b/utils/v4l2-compliance/v4l2-test-buffers.cpp
> index 6d592c9b..130c11fb 100644
> --- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
> +++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
> @@ -634,7 +634,6 @@ int testReqBufs(struct node *node)
>  			fail_on_test(testQueryBuf(node, i, q.g_buffers()));
>  			node->valid_memorytype |= 1 << V4L2_MEMORY_DMABUF;
>  		}
> -
>  		/*
>  		 * It should be possible to set the same std, timings or
>  		 * native size even after reqbufs was called.
> @@ -761,6 +760,47 @@ int testReqBufs(struct node *node)
>  	return 0;
>  }
>  
> +int testCreateBufsMax(struct node *node)
> +{
> +	unsigned int i;
> +	int ret;
> +
> +	node->reopen();
> +
> +	cv4l_queue q(0, 0);
> +
> +	for (i = 1; i <= V4L2_BUF_TYPE_LAST; i++) {
> +		if (!(node->valid_buftypes & (1 << i)))
> +			continue;
> +
> +		q.init(i, V4L2_MEMORY_USERPTR);
> +		ret = q.create_bufs(node, 1);
> +		if (!ret && (q.g_capabilities() & V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS)) {
> +			fail_on_test(q.create_bufs(node, q.g_max_buffers() - q.g_buffers()));
> +			ret = q.create_bufs(node, 1);
> +			fail_on_test(ret != ENOBUFS && (q.g_max_buffers() == q.g_buffers()));
> +		}
> +
> +		q.init(i, V4L2_MEMORY_MMAP);
> +		ret = q.create_bufs(node, 1);
> +		if (!ret && (q.g_capabilities() & V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS)) {
> +			fail_on_test(q.create_bufs(node, q.g_max_buffers() - q.g_buffers()));
> +			ret = q.create_bufs(node, 1);
> +			fail_on_test(ret != ENOBUFS && (q.g_max_buffers() == q.g_buffers()));
> +		}
> +
> +		q.init(i, V4L2_MEMORY_DMABUF);
> +		ret = q.create_bufs(node, 1);
> +		if (!ret && (q.g_capabilities() & V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS)) {
> +			fail_on_test(q.create_bufs(node, q.g_max_buffers() - q.g_buffers()));
> +			ret = q.create_bufs(node, 1);
> +			fail_on_test(ret != ENOBUFS && (q.g_max_buffers() == q.g_buffers()));
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  int testExpBuf(struct node *node)
>  {
>  	bool have_expbuf = false;
diff mbox series

Patch

diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index c19441a1..ac5d2980 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -986,6 +986,7 @@  struct v4l2_requestbuffers {
 #define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS		(1 << 4)
 #define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF	(1 << 5)
 #define V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS		(1 << 6)
+#define V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS		(1 << 7)
 
 /**
  * struct v4l2_plane - plane info for multi-planar buffers
@@ -2531,6 +2532,9 @@  struct v4l2_dbg_chip_info {
  * @flags:	additional buffer management attributes (ignored unless the
  *		queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability
  *		and configured for MMAP streaming I/O).
+ * @max_buffers: if V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS capability flag is set
+ *		 this field indicate the maximum possible number of buffers
+ *		 for this queue.
  * @reserved:	future extensions
  */
 struct v4l2_create_buffers {
@@ -2540,7 +2544,8 @@  struct v4l2_create_buffers {
 	struct v4l2_format	format;
 	__u32			capabilities;
 	__u32			flags;
-	__u32			reserved[6];
+	__u32			max_buffers;
+	__u32			reserved[5];
 };
 
 /*
diff --git a/utils/common/cv4l-helpers.h b/utils/common/cv4l-helpers.h
index 91a04146..5a515a13 100644
--- a/utils/common/cv4l-helpers.h
+++ b/utils/common/cv4l-helpers.h
@@ -743,6 +743,7 @@  public:
 	unsigned g_type() const { return v4l_queue_g_type(this); }
 	unsigned g_memory() const { return v4l_queue_g_memory(this); }
 	unsigned g_buffers() const { return v4l_queue_g_buffers(this); }
+	unsigned g_max_buffers() const { return v4l_queue_g_max_buffers(this); }
 	unsigned g_num_planes() const { return v4l_queue_g_num_planes(this); }
 	unsigned g_capabilities() const { return v4l_queue_g_capabilities(this); }
 	unsigned g_length(unsigned plane) const { return v4l_queue_g_length(this, plane); }
diff --git a/utils/common/v4l-helpers.h b/utils/common/v4l-helpers.h
index f8e96d58..5853f753 100644
--- a/utils/common/v4l-helpers.h
+++ b/utils/common/v4l-helpers.h
@@ -1429,6 +1429,7 @@  struct v4l_queue {
 	unsigned mappings;
 	unsigned num_planes;
 	unsigned capabilities;
+	unsigned max_buffers;
 
 	__u32 lengths[VIDEO_MAX_PLANES];
 	__u32 mem_offsets[VIDEO_MAX_FRAME][VIDEO_MAX_PLANES];
@@ -1453,6 +1454,7 @@  static inline void v4l_queue_init(struct v4l_queue *q,
 static inline unsigned v4l_queue_g_type(const struct v4l_queue *q) { return q->type; }
 static inline unsigned v4l_queue_g_memory(const struct v4l_queue *q) { return q->memory; }
 static inline unsigned v4l_queue_g_buffers(const struct v4l_queue *q) { return q->buffers; }
+static inline unsigned v4l_queue_g_max_buffers(const struct v4l_queue *q) { return q->max_buffers; }
 static inline unsigned v4l_queue_g_mappings(const struct v4l_queue *q) { return q->mappings; }
 static inline unsigned v4l_queue_g_num_planes(const struct v4l_queue *q) { return q->num_planes; }
 static inline unsigned v4l_queue_g_capabilities(const struct v4l_queue *q) { return q->capabilities; }
@@ -1587,6 +1589,9 @@  static inline int v4l_queue_create_bufs(struct v4l_fd *f,
 	if (ret)
 		return ret;
 	q->capabilities = createbufs.capabilities;
+	q->max_buffers = 32;
+	if (q->capabilities & V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS)
+		q->max_buffers = createbufs.max_buffers;
 	q->buffers += createbufs.count;
 	return v4l_queue_querybufs(f, q, q->buffers - createbufs.count);
 }
diff --git a/utils/common/v4l2-info.cpp b/utils/common/v4l2-info.cpp
index 4f8c2aa7..7adfedfc 100644
--- a/utils/common/v4l2-info.cpp
+++ b/utils/common/v4l2-info.cpp
@@ -206,6 +206,7 @@  static constexpr flag_def bufcap_def[] = {
 	{ V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS, "orphaned-bufs" },
 	{ V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF, "m2m-hold-capture-buf" },
 	{ V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS, "mmap-cache-hints" },
+	{ V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS, "set-max-bufs" },
 	{ 0, nullptr }
 };
 
diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp
index f62016e5..56190448 100644
--- a/utils/v4l2-compliance/v4l2-compliance.cpp
+++ b/utils/v4l2-compliance/v4l2-compliance.cpp
@@ -1448,6 +1448,7 @@  void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_
 
 		printf("Buffer ioctls%s:\n", suffix);
 		printf("\ttest VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: %s\n", ok(testReqBufs(&node)));
+		printf("\ttest CREATE_BUFS maximum buffers: %s\n", ok(testCreateBufsMax(&node)));
 		// Reopen after each streaming test to reset the streaming state
 		// in case of any errors in the preceeding test.
 		node.reopen();
diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h
index 7caf254b..4886e4c8 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -383,6 +383,7 @@  int testReqBufs(struct node *node);
 int testReadWrite(struct node *node);
 int testExpBuf(struct node *node);
 int testBlockingWait(struct node *node);
+int testCreateBufsMax(struct node *node);
 
 // 32-bit architecture, 32/64-bit time_t tests
 int testTime32_64(struct node *node);
diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp b/utils/v4l2-compliance/v4l2-test-buffers.cpp
index 6d592c9b..130c11fb 100644
--- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
+++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
@@ -634,7 +634,6 @@  int testReqBufs(struct node *node)
 			fail_on_test(testQueryBuf(node, i, q.g_buffers()));
 			node->valid_memorytype |= 1 << V4L2_MEMORY_DMABUF;
 		}
-
 		/*
 		 * It should be possible to set the same std, timings or
 		 * native size even after reqbufs was called.
@@ -761,6 +760,47 @@  int testReqBufs(struct node *node)
 	return 0;
 }
 
+int testCreateBufsMax(struct node *node)
+{
+	unsigned int i;
+	int ret;
+
+	node->reopen();
+
+	cv4l_queue q(0, 0);
+
+	for (i = 1; i <= V4L2_BUF_TYPE_LAST; i++) {
+		if (!(node->valid_buftypes & (1 << i)))
+			continue;
+
+		q.init(i, V4L2_MEMORY_USERPTR);
+		ret = q.create_bufs(node, 1);
+		if (!ret && (q.g_capabilities() & V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS)) {
+			fail_on_test(q.create_bufs(node, q.g_max_buffers() - q.g_buffers()));
+			ret = q.create_bufs(node, 1);
+			fail_on_test(ret != ENOBUFS && (q.g_max_buffers() == q.g_buffers()));
+		}
+
+		q.init(i, V4L2_MEMORY_MMAP);
+		ret = q.create_bufs(node, 1);
+		if (!ret && (q.g_capabilities() & V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS)) {
+			fail_on_test(q.create_bufs(node, q.g_max_buffers() - q.g_buffers()));
+			ret = q.create_bufs(node, 1);
+			fail_on_test(ret != ENOBUFS && (q.g_max_buffers() == q.g_buffers()));
+		}
+
+		q.init(i, V4L2_MEMORY_DMABUF);
+		ret = q.create_bufs(node, 1);
+		if (!ret && (q.g_capabilities() & V4L2_BUF_CAP_SUPPORTS_SET_MAX_BUFS)) {
+			fail_on_test(q.create_bufs(node, q.g_max_buffers() - q.g_buffers()));
+			ret = q.create_bufs(node, 1);
+			fail_on_test(ret != ENOBUFS && (q.g_max_buffers() == q.g_buffers()));
+		}
+	}
+
+	return 0;
+}
+
 int testExpBuf(struct node *node)
 {
 	bool have_expbuf = false;