All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] drm/msm, media: define the UBWC buffer layout
@ 2026-11-04 16:36 Dmitry Baryshkov
  2026-11-04 16:36 ` [PATCH 1/7] drm/msm/dpu: fix the comment on the RGB UBWC plane count Dmitry Baryshkov
                   ` (6 more replies)
  0 siblings, 7 replies; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-11-04 16:36 UTC (permalink / raw)
  To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
	Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
	Mauro Carvalho Chehab, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Bryan O'Donoghue, Stanimir Varbanov
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jordan Crouse,
	linux-media, Nicolas Dufresne, Vikash Garodia, Dikshita Agarwal,
	Robert Mader, Neil Armstrong

The layout of UBWC buffers (DRM_FORMAT_MOD_QCOM_COMPRESSED, V4L2 QC08C
and QC10C) has never been written down. The V4L2 formats are documented
as opaque with four or eight planes, the DRM modifier as "macrotiles".
In practice the video decoders, the GPU and the display controller
exchange these buffers, so each side has to reverse-engineer the layout
from the other drivers. Nicolas Dufresne asked for a contract to know
what the V4L2 plugins have to compute when passing decoded frames to
DRM.

Writing it down showed that the display driver never validated it:
msm_framebuffer_init() checks UBWC framebuffers as linear ones, so short
buffers are accepted and the DPU reads past their end. Patch 1 fixes a
misleading comment in that code, patch 2 moves the layout calculation
out of DPU, patch 3 checks framebuffers against it.

Patches 4-5 document the layout for DRM and V4L2: metadata followed by
data in each plane, strides, line counts, tile sizes and alignment,
with the chroma size rounded up as DPU and the vendor headers do. For
NV12 the CbCr plane follows the Y plane in the first buffer: DPU has
always fetched it from there, ignoring offsets[1] and pitches[1], and
turnip reports offset 0 for both planes, so this is what existing
userspace relies on.

Patches 6-7 bring Venus and Iris in line with the documented QC10C
layout: Venus reported a wrong bytesperline, Iris called the format P010.

Mesa 26.3-rc rounds the NV12 chroma size down for odd sizes; that is
being fixed on the Mesa side, before the layout reaches a release.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
Dmitry Baryshkov (7):
      drm/msm/dpu: fix the comment on the RGB UBWC plane count
      drm/msm: move the UBWC plane size calculation out of DPU
      drm/msm: check UBWC framebuffers against their layout
      drm/fourcc: describe the Qualcomm UBWC layout
      media: docs: pixfmt-reserved: describe the QC08C and QC10C layout
      media: venus: report the QC10C data stride
      media: qcom: iris: describe QC10C as TP10

 .../userspace-api/media/v4l/pixfmt-reserved.rst    |  63 +++++++++++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c        |  84 +----------------
 drivers/gpu/drm/msm/disp/mdp_format.c              | 100 +++++++++++++++++++++
 drivers/gpu/drm/msm/msm_drv.h                      |   3 +
 drivers/gpu/drm/msm/msm_fb.c                       |  39 ++++++--
 drivers/media/platform/qcom/iris/iris_buffer.c     |   2 +-
 drivers/media/platform/qcom/venus/vdec.c           |   5 +-
 include/uapi/drm/drm_fourcc.h                      |  54 +++++++++--
 8 files changed, 247 insertions(+), 103 deletions(-)
---
base-commit: f1ac44c32cba88ad65dcecd4a279661d14e93651
change-id: 20261027-ubwc-format-docs-7942079e1472

Best regards,
--  
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/7] drm/msm/dpu: fix the comment on the RGB UBWC plane count
  2026-11-04 16:36 [PATCH 0/7] drm/msm, media: define the UBWC buffer layout Dmitry Baryshkov
@ 2026-11-04 16:36 ` Dmitry Baryshkov
  2026-11-04 16:36 ` [PATCH 2/7] drm/msm: move the UBWC plane size calculation out of DPU Dmitry Baryshkov
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-11-04 16:36 UTC (permalink / raw)
  To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
	Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
	Mauro Carvalho Chehab, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Bryan O'Donoghue, Stanimir Varbanov
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jordan Crouse,
	linux-media, Nicolas Dufresne, Vikash Garodia, Dikshita Agarwal,
	Robert Mader, Neil Armstrong

The comment above the num_planes adjustment for RGB UBWC formats says
that the uAPI leaves plane[1] empty, but the uAPI has nothing to do with
it: an RGB UBWC framebuffer has a single plane, with the metadata in
front of the data. The empty slot is in the DPU layout, which follows
the SSPP SRC0-3 address registers. The RGB metadata is fetched through
SRC2 and SRC1 is not used, so num_planes has to cover slot 2. Say so.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
index 590922c4f69b..a8e9a69834af 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
@@ -126,7 +126,7 @@ static int _dpu_format_populate_plane_sizes_ubwc(
 		if (!meta)
 			return 0;
 
-		/* uAPI leaves plane[1] empty and plane[2] as meta */
+		/* RGB metadata is fetched through SRC2, SRC1 stays unused */
 		layout->num_planes += 1;
 
 		rgb_meta_stride = DIV_ROUND_UP(fb->width, 16);

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/7] drm/msm: move the UBWC plane size calculation out of DPU
  2026-11-04 16:36 [PATCH 0/7] drm/msm, media: define the UBWC buffer layout Dmitry Baryshkov
  2026-11-04 16:36 ` [PATCH 1/7] drm/msm/dpu: fix the comment on the RGB UBWC plane count Dmitry Baryshkov
@ 2026-11-04 16:36 ` Dmitry Baryshkov
  2026-11-04 16:36 ` [PATCH 3/7] drm/msm: check UBWC framebuffers against their layout Dmitry Baryshkov
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-11-04 16:36 UTC (permalink / raw)
  To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
	Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
	Mauro Carvalho Chehab, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Bryan O'Donoghue, Stanimir Varbanov
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jordan Crouse,
	linux-media, Nicolas Dufresne, Vikash Garodia, Dikshita Agarwal,
	Robert Mader, Neil Armstrong

The layout of a UBWC framebuffer is only known to the DPU, which computes
it from the framebuffer at atomic check time.  msm_framebuffer_init()
cannot check such a framebuffer against its layout, so it applies the
linear size check instead, which neither matches what the DPU fetches
nor what userspace allocates.

Move the calculation next to mdp_get_format() and make it take the
format and the image size instead of the framebuffer, so that it can be
used before the framebuffer is created.  No functional change.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c |  84 ++---------------------
 drivers/gpu/drm/msm/disp/mdp_format.c       | 100 ++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/msm_drv.h               |   3 +
 3 files changed, 107 insertions(+), 80 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
index a8e9a69834af..06903325e7e7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
@@ -10,8 +10,6 @@
 #include "dpu_kms.h"
 #include "dpu_formats.h"
 
-#define DPU_UBWC_PLANE_SIZE_ALIGNMENT	4096
-
 /*
  * struct dpu_media_color_map - maps drm format to media format
  * @format: DRM base pixel format
@@ -58,87 +56,13 @@ static int _dpu_format_populate_plane_sizes_ubwc(
 		struct drm_framebuffer *fb,
 		struct dpu_hw_fmt_layout *layout)
 {
-	bool meta = MSM_FORMAT_IS_UBWC(fmt);
-
-	if (MSM_FORMAT_IS_YUV(fmt)) {
-		unsigned int stride, y_sclines, uv_sclines;
-		unsigned int y_tile_width, y_tile_height;
-		unsigned int y_meta_stride, y_meta_scanlines;
-		unsigned int uv_meta_stride, uv_meta_scanlines;
-
-		if (MSM_FORMAT_IS_DX(fmt)) {
-			if (fmt->flags & MSM_FORMAT_FLAG_UNPACK_TIGHT) {
-				/* can't use round_up() here because 192 is NPoT */
-				stride = roundup(fb->width, 192);
-				stride = round_up(stride * 4 / 3, 256);
-				y_tile_width = 48;
-			} else {
-				stride = round_up(fb->width * 2, 256);
-				y_tile_width = 32;
-			}
-
-			y_sclines = round_up(fb->height, 16);
-			uv_sclines = round_up((fb->height+1)>>1, 16);
-			y_tile_height = 4;
-		} else {
-			stride = round_up(fb->width, 128);
-			y_tile_width = 32;
-
-			y_sclines = round_up(fb->height, 32);
-			uv_sclines = round_up((fb->height+1)>>1, 32);
-			y_tile_height = 8;
-		}
-
-		layout->plane_pitch[0] = stride;
-		layout->plane_size[0] = round_up(layout->plane_pitch[0] *
-			y_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
-
-		layout->plane_pitch[1] = stride;
-		layout->plane_size[1] = round_up(layout->plane_pitch[1] *
-			uv_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
-
-		if (!meta)
-			return 0;
-
-		y_meta_stride = DIV_ROUND_UP(fb->width, y_tile_width);
-		layout->plane_pitch[2] = round_up(y_meta_stride, 64);
+	mdp_format_ubwc_plane_sizes(fmt, fb->width, fb->height,
+				    layout->plane_pitch, layout->plane_size);
 
-		y_meta_scanlines = DIV_ROUND_UP(fb->height, y_tile_height);
-		y_meta_scanlines = round_up(y_meta_scanlines, 16);
-		layout->plane_size[2] = round_up(layout->plane_pitch[2] *
-			y_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
-
-		uv_meta_stride = DIV_ROUND_UP((fb->width+1)>>1, y_tile_width / 2);
-		layout->plane_pitch[3] = round_up(uv_meta_stride, 64);
-
-		uv_meta_scanlines = DIV_ROUND_UP((fb->height+1)>>1, y_tile_height);
-		uv_meta_scanlines = round_up(uv_meta_scanlines, 16);
-		layout->plane_size[3] = round_up(layout->plane_pitch[3] *
-			uv_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
-	} else {
-		unsigned int rgb_scanlines, rgb_meta_scanlines, rgb_meta_stride;
-
-		layout->plane_pitch[0] = round_up(fb->width * fmt->bpp, 256);
-		rgb_scanlines = round_up(fb->height, 16);
-		layout->plane_size[0] = round_up(layout->plane_pitch[0] *
-			rgb_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
-
-		if (!meta)
-			return 0;
-
-		/* RGB metadata is fetched through SRC2, SRC1 stays unused */
+	/* RGB metadata is fetched through SRC2, SRC1 stays unused */
+	if (!MSM_FORMAT_IS_YUV(fmt) && MSM_FORMAT_IS_UBWC(fmt))
 		layout->num_planes += 1;
 
-		rgb_meta_stride = DIV_ROUND_UP(fb->width, 16);
-		layout->plane_pitch[2] = round_up(rgb_meta_stride, 64);
-
-		rgb_meta_scanlines = DIV_ROUND_UP(fb->height, 4);
-		rgb_meta_scanlines = round_up(rgb_meta_scanlines, 16);
-
-		layout->plane_size[2] = round_up(layout->plane_pitch[2] *
-			rgb_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
-	}
-
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/msm/disp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c
index 33da569eae5e..c0121d709110 100644
--- a/drivers/gpu/drm/msm/disp/mdp_format.c
+++ b/drivers/gpu/drm/msm/disp/mdp_format.c
@@ -650,6 +650,106 @@ const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format,
 	return NULL;
 }
 
+#define MSM_UBWC_PLANE_SIZE_ALIGNMENT	4096
+
+/**
+ * mdp_format_ubwc_plane_sizes - compute the layout of a UBWC or tiled buffer
+ * @fmt: format, which must use MDP_FETCH_UBWC
+ * @width: image width
+ * @height: image height
+ * @pitch: per-plane pitches
+ * @size: per-plane sizes
+ *
+ * Plane indices follow the hardware: 0 is the Y or RGB data, 1 the CbCr data,
+ * 2 the Y or RGB metadata and 3 the CbCr metadata.  Planes not used by the
+ * format are set to zero.
+ */
+void mdp_format_ubwc_plane_sizes(const struct msm_format *fmt,
+				 unsigned int width, unsigned int height,
+				 u32 pitch[4], u32 size[4])
+{
+	bool meta = MSM_FORMAT_IS_UBWC(fmt);
+
+	memset(pitch, 0, 4 * sizeof(*pitch));
+	memset(size, 0, 4 * sizeof(*size));
+
+	if (MSM_FORMAT_IS_YUV(fmt)) {
+		unsigned int stride, y_sclines, uv_sclines;
+		unsigned int y_tile_width, y_tile_height;
+		unsigned int y_meta_stride, y_meta_scanlines;
+		unsigned int uv_meta_stride, uv_meta_scanlines;
+
+		if (MSM_FORMAT_IS_DX(fmt)) {
+			if (fmt->flags & MSM_FORMAT_FLAG_UNPACK_TIGHT) {
+				/* can't use round_up() here because 192 is NPoT */
+				stride = roundup(width, 192);
+				stride = round_up(stride * 4 / 3, 256);
+				y_tile_width = 48;
+			} else {
+				stride = round_up(width * 2, 256);
+				y_tile_width = 32;
+			}
+
+			y_sclines = round_up(height, 16);
+			uv_sclines = round_up((height + 1) >> 1, 16);
+			y_tile_height = 4;
+		} else {
+			stride = round_up(width, 128);
+			y_tile_width = 32;
+
+			y_sclines = round_up(height, 32);
+			uv_sclines = round_up((height + 1) >> 1, 32);
+			y_tile_height = 8;
+		}
+
+		pitch[0] = stride;
+		size[0] = round_up(pitch[0] * y_sclines,
+				   MSM_UBWC_PLANE_SIZE_ALIGNMENT);
+
+		pitch[1] = stride;
+		size[1] = round_up(pitch[1] * uv_sclines,
+				   MSM_UBWC_PLANE_SIZE_ALIGNMENT);
+
+		if (!meta)
+			return;
+
+		y_meta_stride = DIV_ROUND_UP(width, y_tile_width);
+		pitch[2] = round_up(y_meta_stride, 64);
+
+		y_meta_scanlines = DIV_ROUND_UP(height, y_tile_height);
+		y_meta_scanlines = round_up(y_meta_scanlines, 16);
+		size[2] = round_up(pitch[2] * y_meta_scanlines,
+				   MSM_UBWC_PLANE_SIZE_ALIGNMENT);
+
+		uv_meta_stride = DIV_ROUND_UP((width + 1) >> 1, y_tile_width / 2);
+		pitch[3] = round_up(uv_meta_stride, 64);
+
+		uv_meta_scanlines = DIV_ROUND_UP((height + 1) >> 1, y_tile_height);
+		uv_meta_scanlines = round_up(uv_meta_scanlines, 16);
+		size[3] = round_up(pitch[3] * uv_meta_scanlines,
+				   MSM_UBWC_PLANE_SIZE_ALIGNMENT);
+	} else {
+		unsigned int rgb_scanlines, rgb_meta_scanlines, rgb_meta_stride;
+
+		pitch[0] = round_up(width * fmt->bpp, 256);
+		rgb_scanlines = round_up(height, 16);
+		size[0] = round_up(pitch[0] * rgb_scanlines,
+				   MSM_UBWC_PLANE_SIZE_ALIGNMENT);
+
+		if (!meta)
+			return;
+
+		rgb_meta_stride = DIV_ROUND_UP(width, 16);
+		pitch[2] = round_up(rgb_meta_stride, 64);
+
+		rgb_meta_scanlines = DIV_ROUND_UP(height, 4);
+		rgb_meta_scanlines = round_up(rgb_meta_scanlines, 16);
+
+		size[2] = round_up(pitch[2] * rgb_meta_scanlines,
+				   MSM_UBWC_PLANE_SIZE_ALIGNMENT);
+	}
+}
+
 struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type type)
 {
 	if (WARN_ON(type >= CSC_MAX))
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 2840e8a5052d..02fde07eb6f6 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -204,6 +204,9 @@ struct msm_drm_private {
 };
 
 const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format, uint64_t modifier);
+void mdp_format_ubwc_plane_sizes(const struct msm_format *fmt,
+				 unsigned int width, unsigned int height,
+				 u32 pitch[4], u32 size[4]);
 
 struct msm_pending_timer;
 

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/7] drm/msm: check UBWC framebuffers against their layout
  2026-11-04 16:36 [PATCH 0/7] drm/msm, media: define the UBWC buffer layout Dmitry Baryshkov
  2026-11-04 16:36 ` [PATCH 1/7] drm/msm/dpu: fix the comment on the RGB UBWC plane count Dmitry Baryshkov
  2026-11-04 16:36 ` [PATCH 2/7] drm/msm: move the UBWC plane size calculation out of DPU Dmitry Baryshkov
@ 2026-11-04 16:36 ` Dmitry Baryshkov
  2026-11-04 16:47   ` sashiko-bot
  2026-11-04 16:36 ` [PATCH 4/7] drm/fourcc: describe the Qualcomm UBWC layout Dmitry Baryshkov
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-11-04 16:36 UTC (permalink / raw)
  To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
	Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
	Mauro Carvalho Chehab, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Bryan O'Donoghue, Stanimir Varbanov
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jordan Crouse,
	linux-media, Nicolas Dufresne, Vikash Garodia, Dikshita Agarwal,
	Robert Mader, Neil Armstrong

msm_framebuffer_init() checks every framebuffer plane as a linear one:
(height - 1) * pitch + width * cpp + offset must fit into the buffer.
For UBWC this has nothing to do with the memory the DPU fetches.  The
metadata and the scanline padding are not accounted for, so a 1080p NV12
framebuffer whose buffer is 15872 bytes short of the UBWC layout is
accepted and the DPU reads past its end.  The CbCr planes are checked
where the DPU does not look: it always fetches them after the Y data in
the first buffer, ignoring handles[1], offsets[1] and pitches[1], and
userspace relies on that (turnip reports offset 0 for both planes).  The
pitches are not checked at all, as the DPU replaces them with its own.

Compute the UBWC layout instead: require the first pitch to match it,
the CbCr plane to be in the first buffer, and check that the metadata
and data of all planes fit into it.

Fixes: 25fdd5933e4c ("drm/msm: Add SDM845 DPU support")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 drivers/gpu/drm/msm/msm_fb.c | 39 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index 1e236416e15f..dd24aa7a5ee8 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -13,6 +13,7 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_probe_helper.h>
 
+#include "disp/mdp_format.h"
 #include "msm_drv.h"
 #include "msm_kms.h"
 #include "msm_gem.h"
@@ -146,6 +147,7 @@ msm_framebuffer_init(struct drm_device *dev, const struct drm_format_info *info,
 	struct msm_framebuffer *msm_fb = NULL;
 	struct drm_framebuffer *fb;
 	const struct msm_format *format;
+	u32 ubwc_pitch[4], ubwc_size[4];
 	int ret, i, n;
 
 	drm_dbg_state(dev, "create framebuffer: mode_cmd=%p (%dx%d@%p4cc)\n",
@@ -177,14 +179,41 @@ msm_framebuffer_init(struct drm_device *dev, const struct drm_format_info *info,
 		goto fail;
 	}
 
+	if (format->fetch_mode == MDP_FETCH_UBWC)
+		mdp_format_ubwc_plane_sizes(format, mode_cmd->width,
+					    mode_cmd->height, ubwc_pitch,
+					    ubwc_size);
+
 	for (i = 0; i < n; i++) {
 		unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
 		unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
-		unsigned int min_size;
-
-		min_size = (height - 1) * mode_cmd->pitches[i]
-			 + width * info->cpp[i]
-			 + mode_cmd->offsets[i];
+		u64 min_size;
+
+		if (format->fetch_mode == MDP_FETCH_UBWC) {
+			/*
+			 * The CbCr planes follow the Y data in the first buffer,
+			 * offsets[1] and pitches[1] are not used.
+			 */
+			if (i > 0) {
+				if (bos[i] != bos[0]) {
+					ret = UERR(EINVAL, dev,
+						   "plane %d not in the first buffer", i);
+					goto fail;
+				}
+				min_size = 0;
+			} else if (mode_cmd->pitches[0] != ubwc_pitch[0]) {
+				ret = UERR(EINVAL, dev, "pitch %u, expected %u",
+					   mode_cmd->pitches[0], ubwc_pitch[0]);
+				goto fail;
+			} else {
+				min_size = (u64)mode_cmd->offsets[0] + ubwc_size[0] +
+					   ubwc_size[1] + ubwc_size[2] + ubwc_size[3];
+			}
+		} else {
+			min_size = (height - 1) * mode_cmd->pitches[i]
+				 + width * info->cpp[i]
+				 + mode_cmd->offsets[i];
+		}
 
 		if (bos[i]->size < min_size) {
 			ret = UERR(EINVAL, dev, "plane %d too small", i);

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/7] drm/fourcc: describe the Qualcomm UBWC layout
  2026-11-04 16:36 [PATCH 0/7] drm/msm, media: define the UBWC buffer layout Dmitry Baryshkov
                   ` (2 preceding siblings ...)
  2026-11-04 16:36 ` [PATCH 3/7] drm/msm: check UBWC framebuffers against their layout Dmitry Baryshkov
@ 2026-11-04 16:36 ` Dmitry Baryshkov
  2026-11-04 16:46   ` sashiko-bot
  2026-11-04 16:36 ` [PATCH 5/7] media: docs: pixfmt-reserved: describe the QC08C and QC10C layout Dmitry Baryshkov
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-11-04 16:36 UTC (permalink / raw)
  To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
	Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
	Mauro Carvalho Chehab, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Bryan O'Donoghue, Stanimir Varbanov
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jordan Crouse,
	linux-media, Nicolas Dufresne, Vikash Garodia, Dikshita Agarwal,
	Robert Mader, Neil Armstrong

The DRM_FORMAT_MOD_QCOM_COMPRESSED description talks about macrotiles
but does not say where the metadata is, what the pitch refers to or how
large the planes are. The msm driver derives all of that from the width
and the height, and the GPU drivers and video decoders allocate buffers
to match, so the layout is uAPI whether it is written down or not.

Document it for the formats the display controller supports: the
metadata before the data in each plane, the tile sizes and alignments,
and the CbCr plane following the Y plane in the first buffer. The
display controller has always fetched it from there, ignoring
offsets[1] and pitches[1], and existing userspace depends on it: turnip
reports offset 0 for both planes. Note that P010 stores 16-bit samples,
unlike the packed V4L2 QC10C format.

The layout is stricter than the display controller or the camera need,
as they can address the metadata and the data of each plane separately,
but other users depend on it. The video firmware takes a single address
per frame and places all four sections itself, and the Adreno texture
descriptor for multi-planar YUV has only one address per plane, finding
the data after the metadata. Buffers shared with these devices have
to follow it.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 include/uapi/drm/drm_fourcc.h | 54 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 47 insertions(+), 7 deletions(-)

diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 0bb049f91524..4b6a4a827f6b 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -820,13 +820,53 @@ extern "C" {
 /*
  * Qualcomm Compressed Format
  *
- * Refers to a compressed variant of the base format that is compressed.
- * Implementation may be platform and base-format specific.
- *
- * Each macrotile consists of m x n (mostly 4 x 4) tiles.
- * Pixel data pitch/stride is aligned with macrotile width.
- * Pixel data height is aligned with macrotile height.
- * Entire pixel data buffer is aligned with 4k(bytes).
+ * Universal Bandwidth Compression (UBWC), a lossless compression used by the
+ * GPU, display controller, video accelerators and camera. The compressed
+ * contents depend on the UBWC version and memory configuration of the
+ * platform and are only meant to be accessed by the hardware. The layout of
+ * the buffer depends only on the format and the size.
+ *
+ * Each plane consists of a metadata section followed by a data section, and
+ * the planes follow each other, all in the buffer referenced by handles[0],
+ * starting at offsets[0]. Each section starts on a 4096-byte boundary and its
+ * size is rounded up to a multiple of 4096 bytes. The metadata holds one byte
+ * for each tile of the data. pitches[0] is the stride of the first plane's
+ * data and must match the value below; all other strides and offsets are
+ * computed from the width and height of the framebuffer.
+ *
+ * For a width x height framebuffer, with subsampled planes being
+ * DIV_ROUND_UP(width, 2) x DIV_ROUND_UP(height, 2) samples:
+ *
+ * RGB formats with 2 or 4 bytes per pixel (cpp), one plane:
+ *   data: pitch ALIGN(width * cpp, 256), ALIGN(height, 16) lines
+ *   metadata: 16x4 pixel tiles, stride ALIGN(DIV_ROUND_UP(width, 16), 64),
+ *   ALIGN(DIV_ROUND_UP(height, 4), 16) lines
+ *
+ * DRM_FORMAT_NV12, two planes, Y then CbCr (V4L2_PIX_FMT_QC08C):
+ *   Y data: pitch ALIGN(width, 128), ALIGN(height, 32) lines
+ *   Y metadata: 32x8 pixel tiles, stride ALIGN(DIV_ROUND_UP(width, 32), 64),
+ *   ALIGN(DIV_ROUND_UP(height, 8), 16) lines
+ *   CbCr data: pitch ALIGN(width, 128),
+ *   ALIGN(DIV_ROUND_UP(height, 2), 32) lines
+ *   CbCr metadata: 16x8 sample tiles,
+ *   stride ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(width, 2), 16), 64),
+ *   ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(height, 2), 8), 16) lines
+ *
+ * DRM_FORMAT_P010, two planes, Y then CbCr, 16 bits per sample:
+ *   Y data: pitch ALIGN(width * 2, 256), ALIGN(height, 16) lines
+ *   Y metadata: 32x4 pixel tiles, stride ALIGN(DIV_ROUND_UP(width, 32), 64),
+ *   ALIGN(DIV_ROUND_UP(height, 4), 16) lines
+ *   CbCr data: pitch ALIGN(width * 2, 256),
+ *   ALIGN(DIV_ROUND_UP(height, 2), 16) lines
+ *   CbCr metadata: 16x4 sample tiles,
+ *   stride ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(width, 2), 16), 64),
+ *   ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(height, 2), 4), 16) lines
+ *
+ * Two-plane images are allocated as a single buffer holding both planes,
+ * with the CbCr metadata following the Y data, so the CbCr plane starts at
+ * offsets[0] + Y metadata size + Y data size. handles[1] must refer to the
+ * same buffer as handles[0]; offsets[1] and pitches[1] are ignored, userspace
+ * should set them to the CbCr plane offset and the CbCr data stride.
  */
 #define DRM_FORMAT_MOD_QCOM_COMPRESSED	fourcc_mod_code(QCOM, 1)
 

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/7] media: docs: pixfmt-reserved: describe the QC08C and QC10C layout
  2026-11-04 16:36 [PATCH 0/7] drm/msm, media: define the UBWC buffer layout Dmitry Baryshkov
                   ` (3 preceding siblings ...)
  2026-11-04 16:36 ` [PATCH 4/7] drm/fourcc: describe the Qualcomm UBWC layout Dmitry Baryshkov
@ 2026-11-04 16:36 ` Dmitry Baryshkov
  2026-11-04 16:36 ` [PATCH 6/7] media: venus: report the QC10C data stride Dmitry Baryshkov
  2026-11-04 16:36 ` [PATCH 7/7] media: qcom: iris: describe QC10C as TP10 Dmitry Baryshkov
  6 siblings, 0 replies; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-11-04 16:36 UTC (permalink / raw)
  To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
	Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
	Mauro Carvalho Chehab, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Bryan O'Donoghue, Stanimir Varbanov
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jordan Crouse,
	linux-media, Nicolas Dufresne, Vikash Garodia, Dikshita Agarwal,
	Robert Mader, Neil Armstrong

QC08C and QC10C are documented as opaque formats with four planes, or
eight for interlaced video. Neither is true for the drivers: Venus and
Iris use a single memory plane, nothing produces interlaced buffers, and
the display controller and the GPU import these buffers, so the layout
is part of the contract between them.

Describe the sections of the buffer, their order, strides, line counts
and alignment. The compressed contents stay opaque, they depend on the
UBWC configuration of the platform.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 .../userspace-api/media/v4l/pixfmt-reserved.rst    | 63 ++++++++++++++++++----
 1 file changed, 54 insertions(+), 9 deletions(-)

diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
index 1cf6c59f4bc4..3ff6499970e1 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
@@ -245,20 +245,65 @@ please make a proposal on the linux-media mailing list.
       - ``V4L2_PIX_FMT_QC08C``
       - 'QC08C'
       - Compressed Macro-tile 8-Bit YUV420 format used by Qualcomm platforms.
-        It is an opaque intermediate format. The used compression is lossless
-        and it is used by various multimedia hardware blocks like GPU, display
-        controllers, ISP and video accelerators.
-        It contains four planes for progressive video and eight planes for
-        interlaced video.
+        This is NV12 compressed with Universal Bandwidth Compression (UBWC),
+        a lossless compression used by the video accelerators, GPU, display
+        controller and camera. The compressed contents depend on the UBWC
+        version and memory configuration of the platform and are only meant
+        to be accessed by the hardware; the layout of the buffer is defined
+        below.
+
+        The format uses a single memory plane that holds four sections in
+        this order: Y metadata, Y data, CbCr metadata and CbCr data. Each
+        section starts at the beginning of the previous section plus its
+        size, which is rounded up to a multiple of 4096 bytes. The metadata
+        holds one byte for each tile of the data. ``bytesperline`` is the
+        stride of the Y and CbCr data. For a ``width`` x ``height`` buffer,
+        with the CbCr plane being ``DIV_ROUND_UP(width, 2)`` x
+        ``DIV_ROUND_UP(height, 2)`` samples:
+
+        - Y data: stride ``ALIGN(width, 128)`` bytes,
+          ``ALIGN(height, 32)`` lines.
+        - CbCr data: stride ``ALIGN(width, 128)`` bytes,
+          ``ALIGN(DIV_ROUND_UP(height, 2), 32)`` lines.
+        - Y metadata: 32x8 pixel tiles, stride
+          ``ALIGN(DIV_ROUND_UP(width, 32), 64)`` bytes,
+          ``ALIGN(DIV_ROUND_UP(height, 8), 16)`` lines.
+        - CbCr metadata: 16x8 sample tiles, stride
+          ``ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(width, 2), 16), 64)`` bytes,
+          ``ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(height, 2), 8), 16)`` lines.
+
+        ``sizeimage`` may be larger than the sum of the sections.
+        The same layout is described by ``DRM_FORMAT_NV12`` with the
+        ``DRM_FORMAT_MOD_QCOM_COMPRESSED`` modifier, with both DRM planes
+        referring to the same buffer and the Y metadata at ``offsets[0]``.
     * .. _V4L2-PIX-FMT-QC10C:
 
       - ``V4L2_PIX_FMT_QC10C``
       - 'QC10C'
       - Compressed Macro-tile 10-Bit YUV420 format used by Qualcomm platforms.
-        It is an opaque intermediate format. The used compression is lossless
-        and it is used by various multimedia hardware blocks like GPU, display
-        controllers, ISP and video accelerators.
-        It contains four planes for progressive video.
+        This is the TP10 format, YUV420 with three 10-bit samples tightly
+        packed in each 32-bit word, in both the Y plane and the interleaved
+        CbCr plane, compressed with UBWC as described for
+        ``V4L2_PIX_FMT_QC08C``. Each 192 samples of a line take 256 bytes.
+
+        The format uses a single memory plane with the same four sections as
+        ``V4L2_PIX_FMT_QC08C``. ``bytesperline`` is the stride of the Y and
+        CbCr data. For a ``width`` x ``height`` buffer:
+
+        - Y data: stride ``DIV_ROUND_UP(width, 192) * 256`` bytes,
+          ``ALIGN(height, 16)`` lines.
+        - CbCr data: stride ``DIV_ROUND_UP(width, 192) * 256`` bytes,
+          ``ALIGN(DIV_ROUND_UP(height, 2), 16)`` lines.
+        - Y metadata: 48x4 pixel tiles, stride
+          ``ALIGN(DIV_ROUND_UP(width, 48), 64)`` bytes,
+          ``ALIGN(DIV_ROUND_UP(height, 4), 16)`` lines.
+        - CbCr metadata: 24x4 sample tiles, stride
+          ``ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(width, 2), 24), 64)`` bytes,
+          ``ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(height, 2), 4), 16)`` lines.
+
+        ``sizeimage`` may be larger than the sum of the sections. There is
+        no DRM equivalent: ``DRM_FORMAT_P010`` with the
+        ``DRM_FORMAT_MOD_QCOM_COMPRESSED`` modifier stores 16-bit samples.
     * .. _V4L2-PIX-FMT-AJPG:
 
       - ``V4L2_PIX_FMT_AJPG``

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/7] media: venus: report the QC10C data stride
  2026-11-04 16:36 [PATCH 0/7] drm/msm, media: define the UBWC buffer layout Dmitry Baryshkov
                   ` (4 preceding siblings ...)
  2026-11-04 16:36 ` [PATCH 5/7] media: docs: pixfmt-reserved: describe the QC08C and QC10C layout Dmitry Baryshkov
@ 2026-11-04 16:36 ` Dmitry Baryshkov
  2026-11-04 16:36 ` [PATCH 7/7] media: qcom: iris: describe QC10C as TP10 Dmitry Baryshkov
  6 siblings, 0 replies; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-11-04 16:36 UTC (permalink / raw)
  To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
	Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
	Mauro Carvalho Chehab, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Bryan O'Donoghue, Stanimir Varbanov
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jordan Crouse,
	linux-media, Nicolas Dufresne, Vikash Garodia, Dikshita Agarwal,
	Robert Mader, Neil Armstrong

For QC10C capture buffers the decoder reports bytesperline as the width
aligned to 128, as for 8-bit formats. QC10C packs three 10-bit samples
in 32 bits and pads each line to 256 bytes per 192 pixels, so the
reported value is too small: a 1920 pixel line takes 2560 bytes, not
1920. Userspace using bytesperline to import the frame into DRM gets a
wrong pitch.

Report the stride the buffer actually has, as computed for the
buffer size and as Iris already does. The downstream msm_vidc driver
reports VENUS_Y_STRIDE(), which for NV12_BPP10_UBWC is the same
ALIGN(ALIGN(width, 192) * 4 / 3, 256).

Fixes: cef92b14e653 ("media: venus: Add a handling of QC10C compressed format")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 drivers/media/platform/qcom/venus/vdec.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index 6a43ea191da1..9de0c9bc2919 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -227,7 +227,10 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
 			stride *= 2;
 
 		pfmt[0].sizeimage = szimage;
-		pfmt[0].bytesperline = ALIGN(stride, 128);
+		if (pixmp->pixelformat == V4L2_PIX_FMT_QC10C)
+			pfmt[0].bytesperline = DIV_ROUND_UP(pixmp->width, 192) * 256;
+		else
+			pfmt[0].bytesperline = ALIGN(stride, 128);
 	} else {
 		pfmt[0].sizeimage = clamp_t(u32, pfmt[0].sizeimage, 0, SZ_8M);
 		pfmt[0].sizeimage = max(pfmt[0].sizeimage, szimage);

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 7/7] media: qcom: iris: describe QC10C as TP10
  2026-11-04 16:36 [PATCH 0/7] drm/msm, media: define the UBWC buffer layout Dmitry Baryshkov
                   ` (5 preceding siblings ...)
  2026-11-04 16:36 ` [PATCH 6/7] media: venus: report the QC10C data stride Dmitry Baryshkov
@ 2026-11-04 16:36 ` Dmitry Baryshkov
  2026-11-04 18:59   ` Robert Mader
  6 siblings, 1 reply; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-11-04 16:36 UTC (permalink / raw)
  To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
	Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
	Mauro Carvalho Chehab, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Bryan O'Donoghue, Stanimir Varbanov
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jordan Crouse,
	linux-media, Nicolas Dufresne, Vikash Garodia, Dikshita Agarwal,
	Robert Mader, Neil Armstrong

The comment describing the QC10C buffer layout calls it a compressed
P010. It is not: P010 stores each sample in 16 bits, QC10C packs three
10-bit samples in each 32-bit word, which is what the stride computed
below (width * 4 / 3) assumes. Name the format correctly.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 drivers/media/platform/qcom/iris/iris_buffer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c
index eb8de60c1177..ec2bf2a2d953 100644
--- a/drivers/media/platform/qcom/iris/iris_buffer.c
+++ b/drivers/media/platform/qcom/iris/iris_buffer.c
@@ -266,7 +266,7 @@ static u32 iris_yuv_buffer_size_qc08c(struct iris_inst *inst)
 
 /*
  * QC10C:
- * UBWC-compressed format for P010.
+ * UBWC-compressed TP10, YUV 4:2:0 with three 10 bit samples packed in 32 bits.
  * Contains 4 planes in the following order -
  * (A) Y_Meta_Plane
  * (B) Y_UBWC_Plane

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/7] drm/fourcc: describe the Qualcomm UBWC layout
  2026-11-04 16:36 ` [PATCH 4/7] drm/fourcc: describe the Qualcomm UBWC layout Dmitry Baryshkov
@ 2026-11-04 16:46   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-11-04 16:46 UTC (permalink / raw)
  To: Dmitry Baryshkov; +Cc: dri-devel, media-ci

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] drm/fourcc: documented UBWC P010 layout mismatches msm driver
--

commit 9d1d25812fbfd6458cdaf0aaead9ba0fe219bc18
Author: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>

drm/fourcc: describe the Qualcomm UBWC layout

This commit documents the buffer layout, plane ordering, tile sizes, and
alignment requirements for DRM_FORMAT_MOD_QCOM_COMPRESSED across RGB,
DRM_FORMAT_NV12, and DRM_FORMAT_P010 formats.

> diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
> index 0bb049f91524e..4b6a4a827f6b8 100644
> --- a/include/uapi/drm/drm_fourcc.h
> +++ b/include/uapi/drm/drm_fourcc.h
> @@ -820,13 +820,53 @@ extern "C" {

[ ... ]

> + * DRM_FORMAT_P010, two planes, Y then CbCr, 16 bits per sample:
> + *   Y data: pitch ALIGN(width * 2, 256), ALIGN(height, 16) lines
> + *   Y metadata: 32x4 pixel tiles, stride ALIGN(DIV_ROUND_UP(width, 32), 64),
> + *   ALIGN(DIV_ROUND_UP(height, 4), 16) lines
> + *   CbCr data: pitch ALIGN(width * 2, 256),
> + *   ALIGN(DIV_ROUND_UP(height, 2), 16) lines
> + *   CbCr metadata: 16x4 sample tiles,
> + *   stride ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(width, 2), 16), 64),
> + *   ALIGN(DIV_ROUND_UP(DIV_ROUND_UP(height, 2), 4), 16) lines

[Severity: Medium]
Does the documented layout for DRM_FORMAT_P010 match what the msm driver
currently expects for DRM_FORMAT_MOD_QCOM_COMPRESSED?

In drivers/gpu/drm/msm/disp/mdp_format.c, mdp_formats_ubwc[] defines the
compressed P010 entry using PSEUDO_YUV_FMT_TILED, which unconditionally
sets MSM_FORMAT_FLAG_UNPACK_TIGHT:

drivers/gpu/drm/msm/disp/mdp_format.c:
    #define PSEUDO_YUV_FMT_TILED(fmt, a, r, g, b, e0, e1, chroma, flg, tile_height) \
        ...
        .fetch_mode = MDP_FETCH_UBWC,                                     \
        .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT |                           \
                 MSM_FORMAT_FLAG_YUV |                                    \
                 MSM_FORMAT_FLAG_COMPRESSED | flg,                        \

    static const struct msm_format mdp_formats_ubwc[] = {
        ...
        PSEUDO_YUV_FMT_TILED(P010,
            BPC8, BPC8, BPC8,
            C1_B_Cb, C2_R_Cr,
            CHROMA_420, MSM_FORMAT_FLAG_DX,
            MDP_TILE_HEIGHT_UBWC),

When DRM_IOCTL_MODE_ADDFB2 calls msm_framebuffer_create() ->
msm_framebuffer_init() -> mdp_format_ubwc_plane_sizes(), the presence of
MSM_FORMAT_FLAG_UNPACK_TIGHT causes it to take the tightly packed TP10/QC10C
branch instead of the 16-bit per sample else branch described in this
comment:

drivers/gpu/drm/msm/disp/mdp_format.c:mdp_format_ubwc_plane_sizes() {
    ...
    if (MSM_FORMAT_IS_DX(fmt)) {
        if (fmt->flags & MSM_FORMAT_FLAG_UNPACK_TIGHT) {
            /* can't use round_up() here because 192 is NPoT */
            stride = roundup(width, 192);
            stride = round_up(stride * 4 / 3, 256);
            y_tile_width = 48;
        } else {
            stride = round_up(width * 2, 256);
            y_tile_width = 32;
        }
    ...
}

Because msm_framebuffer_init() checks that mode_cmd->pitches[0] equals
ubwc_pitch[0]:

drivers/gpu/drm/msm/msm_fb.c:msm_framebuffer_init() {
    ...
    } else if (mode_cmd->pitches[0] != ubwc_pitch[0]) {
        ret = UERR(EINVAL, dev, "pitch %u, expected %u",
                   mode_cmd->pitches[0], ubwc_pitch[0]);
        goto fail;
    }
    ...
}

won't a DRM_FORMAT_P010 framebuffer allocated with
DRM_FORMAT_MOD_QCOM_COMPRESSED according to this documentation (with pitch
ALIGN(width * 2, 256) and 32x4 Y tiles) be rejected with -EINVAL by
msm_framebuffer_init(), or have the DPU unpacker configured with
UNPACK_TIGHT = 1 and UNPACK_ALIGN_MSB = 0 in dpu_hw_setup_format_impl() and
dpu_hw_wb_setup_format()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261104-ubwc-format-docs-v1-0-389044012b4e@oss.qualcomm.com?part=4

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/7] drm/msm: check UBWC framebuffers against their layout
  2026-11-04 16:36 ` [PATCH 3/7] drm/msm: check UBWC framebuffers against their layout Dmitry Baryshkov
@ 2026-11-04 16:47   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-11-04 16:47 UTC (permalink / raw)
  To: Dmitry Baryshkov; +Cc: dri-devel, media-ci

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] drm/msm: broken P010 UBWC pitch check in msm_framebuffer_init()
--

commit 692349e38091784388304159b902edd6edf3ad3a
Author: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>

drm/msm: check UBWC framebuffers against their layout

This commit updates msm_framebuffer_init() to validate UBWC framebuffers
against their computed UBWC plane pitches and sizes rather than checking
them as linear buffers.

> diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
> index 1e236416e15f0..dd24aa7a5ee80 100644
> --- a/drivers/gpu/drm/msm/msm_fb.c
> +++ b/drivers/gpu/drm/msm/msm_fb.c

[ ... ]

> @@ -177,14 +179,41 @@ msm_framebuffer_init(struct drm_device *dev, const struct drm_format_info *info,
>  		goto fail;
>  	}
>  
> +	if (format->fetch_mode == MDP_FETCH_UBWC)
> +		mdp_format_ubwc_plane_sizes(format, mode_cmd->width,
> +					    mode_cmd->height, ubwc_pitch,
> +					    ubwc_size);
> +
>  	for (i = 0; i < n; i++) {
>  		unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
>  		unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
> -		unsigned int min_size;
> -
> -		min_size = (height - 1) * mode_cmd->pitches[i]
> -			 + width * info->cpp[i]
> -			 + mode_cmd->offsets[i];
> +		u64 min_size;
> +
> +		if (format->fetch_mode == MDP_FETCH_UBWC) {
> +			/*
> +			 * The CbCr planes follow the Y data in the first buffer,
> +			 * offsets[1] and pitches[1] are not used.
> +			 */
> +			if (i > 0) {
> +				if (bos[i] != bos[0]) {
> +					ret = UERR(EINVAL, dev,
> +						   "plane %d not in the first buffer", i);
> +					goto fail;
> +				}
> +				min_size = 0;
> +			} else if (mode_cmd->pitches[0] != ubwc_pitch[0]) {
> +				ret = UERR(EINVAL, dev, "pitch %u, expected %u",
> +					   mode_cmd->pitches[0], ubwc_pitch[0]);
> +				goto fail;

[Severity: High]
Does this break creating DRM_FORMAT_P010 framebuffers with
DRM_FORMAT_MOD_QCOM_COMPRESSED?

In drivers/gpu/drm/msm/disp/mdp_format.c, mdp_formats_ubwc[] defines the
P010 entry using PSEUDO_YUV_FMT_TILED, which sets
MSM_FORMAT_FLAG_UNPACK_TIGHT:

drivers/gpu/drm/msm/disp/mdp_format.c:
	PSEUDO_YUV_FMT_TILED(P010,
		BPC8, BPC8, BPC8,
		C1_B_Cb, C2_R_Cr,
		CHROMA_420, MSM_FORMAT_FLAG_DX,
		MDP_TILE_HEIGHT_UBWC),

When mdp_format_ubwc_plane_sizes() is called on a DX YUV format with
MSM_FORMAT_FLAG_UNPACK_TIGHT set, it computes the tightly-packed TP10
stride (4/3 bytes per pixel) rather than the 2 bytes-per-pixel P010 stride:

drivers/gpu/drm/msm/disp/mdp_format.c:mdp_format_ubwc_plane_sizes() {
	...
		if (MSM_FORMAT_IS_DX(fmt)) {
			if (fmt->flags & MSM_FORMAT_FLAG_UNPACK_TIGHT) {
				/* can't use round_up() here because 192 is NPoT */
				stride = roundup(width, 192);
				stride = round_up(stride * 4 / 3, 256);
				y_tile_width = 48;
			} else {
				stride = round_up(width * 2, 256);
				y_tile_width = 32;
			}
	...
}

However, before msm_framebuffer_init() is reached,
drm_internal_framebuffer_create() -> framebuffer_check() in
drivers/gpu/drm/drm_framebuffer.c checks r->pitches[0] against
drm_format_info_min_pitch() for DRM_FORMAT_P010 (which has
char_per_block[0] = 2 and block_w[0] = 1), rejecting any framebuffer where
pitches[0] < width * 2:

drivers/gpu/drm/drm_framebuffer.c:framebuffer_check() {
	...
		if (block_size && r->pitches[i] < min_pitch) {
			drm_dbg_kms(dev, "bad pitch %u for plane %d\n", r->pitches[i], i);
			return -EINVAL;
		}
	...
}

Because roundup(width, 192) * 4 / 3 is strictly less than width * 2 for all
widths > 256 (as well as 129 <= width <= 192), no pitches[0] value can
satisfy both framebuffer_check() (pitches[0] >= width * 2) and
msm_framebuffer_init() (pitches[0] == ubwc_pitch[0]). For example, at
width = 1920, framebuffer_check() requires pitches[0] >= 3840 while
ubwc_pitch[0] is 2560, causing ADDFB2 to fail unconditionally with -EINVAL.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261104-ubwc-format-docs-v1-0-389044012b4e@oss.qualcomm.com?part=3

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 7/7] media: qcom: iris: describe QC10C as TP10
  2026-11-04 16:36 ` [PATCH 7/7] media: qcom: iris: describe QC10C as TP10 Dmitry Baryshkov
@ 2026-11-04 18:59   ` Robert Mader
  0 siblings, 0 replies; 11+ messages in thread
From: Robert Mader @ 2026-11-04 18:59 UTC (permalink / raw)
  To: Dmitry Baryshkov, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
	Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
	Simona Vetter, Mauro Carvalho Chehab, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Bryan O'Donoghue,
	Stanimir Varbanov
  Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Jordan Crouse,
	linux-media, Nicolas Dufresne, Vikash Garodia, Dikshita Agarwal,
	Neil Armstrong

Nice, very happy to see the series!

On 04.11.26 17:36, Dmitry Baryshkov wrote:
> The comment describing the QC10C buffer layout calls it a compressed
> P010. It is not:

If I'm not mistaken the display engine / the DRM side (including Mesa) 
describes it as P010+QCOM_COMPRESSED as well, and so does my pending 
Gstreamer MR [1] . So if we can't pretend that QC10C == 
P010+QCOM_COMPRESSED, then we probably need a DRM_FORMAT_TP10, wire that 
up everywhere etc. OTOH if we want to keep the DRM side as is, then the 
comment should reflect that, IMO.

Best regards,

Robert

1: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8195

> P010 stores each sample in 16 bits, QC10C packs three
> 10-bit samples in each 32-bit word, which is what the stride computed
> below (width * 4 / 3) assumes. Name the format correctly.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
>   drivers/media/platform/qcom/iris/iris_buffer.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c
> index eb8de60c1177..ec2bf2a2d953 100644
> --- a/drivers/media/platform/qcom/iris/iris_buffer.c
> +++ b/drivers/media/platform/qcom/iris/iris_buffer.c
> @@ -266,7 +266,7 @@ static u32 iris_yuv_buffer_size_qc08c(struct iris_inst *inst)
>   
>   /*
>    * QC10C:
> - * UBWC-compressed format for P010.
> + * UBWC-compressed TP10, YUV 4:2:0 with three 10 bit samples packed in 32 bits.
>    * Contains 4 planes in the following order -
>    * (A) Y_Meta_Plane
>    * (B) Y_UBWC_Plane
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-11-04 19:00 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-04 16:36 [PATCH 0/7] drm/msm, media: define the UBWC buffer layout Dmitry Baryshkov
2026-11-04 16:36 ` [PATCH 1/7] drm/msm/dpu: fix the comment on the RGB UBWC plane count Dmitry Baryshkov
2026-11-04 16:36 ` [PATCH 2/7] drm/msm: move the UBWC plane size calculation out of DPU Dmitry Baryshkov
2026-11-04 16:36 ` [PATCH 3/7] drm/msm: check UBWC framebuffers against their layout Dmitry Baryshkov
2026-11-04 16:47   ` sashiko-bot
2026-11-04 16:36 ` [PATCH 4/7] drm/fourcc: describe the Qualcomm UBWC layout Dmitry Baryshkov
2026-11-04 16:46   ` sashiko-bot
2026-11-04 16:36 ` [PATCH 5/7] media: docs: pixfmt-reserved: describe the QC08C and QC10C layout Dmitry Baryshkov
2026-11-04 16:36 ` [PATCH 6/7] media: venus: report the QC10C data stride Dmitry Baryshkov
2026-11-04 16:36 ` [PATCH 7/7] media: qcom: iris: describe QC10C as TP10 Dmitry Baryshkov
2026-11-04 18:59   ` Robert Mader

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.