[PATCHv4 05/36] drm/gem-fb-helper: Add generic afbc size checks

Andrzej Pietrasiewicz andrzej.p at collabora.com
Fri Dec 13 15:58:36 UTC 2019


Extend the size-checking special function to handle afbc.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p at collabora.com>
---
 drivers/gpu/drm/drm_fourcc.c                 | 10 +++-
 drivers/gpu/drm/drm_framebuffer.c            |  3 +
 drivers/gpu/drm/drm_gem_framebuffer_helper.c | 60 ++++++++++++++++++--
 include/drm/drm_gem_framebuffer_helper.h     | 16 ++++++
 4 files changed, 82 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index d14dd7c86020..9ac2175c5bee 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -323,8 +323,14 @@ drm_get_format_info(struct drm_device *dev,
 {
 	const struct drm_format_info *info = NULL;
 
-	if (dev->mode_config.funcs->get_format_info)
-		info = dev->mode_config.funcs->get_format_info(mode_cmd);
+	/* bypass driver callback if afbc */
+	if (!drm_is_afbc(mode_cmd->modifier[0]))
+		if (dev->mode_config.funcs->get_format_info) {
+			const struct drm_mode_config_funcs *funcs;
+
+			funcs = dev->mode_config.funcs;
+			info = funcs->get_format_info(mode_cmd);
+		}
 
 	if (!info)
 		info = drm_format_info(mode_cmd->pixel_format);
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 57564318ceea..33b741cc73e8 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -204,6 +204,9 @@ static int framebuffer_check(struct drm_device *dev,
 		unsigned int block_size = info->char_per_block[i];
 		u64 min_pitch = drm_format_info_min_pitch(info, i, width);
 
+		if (drm_is_afbc(r->modifier[i]))
+			block_size = 0;
+
 		if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) {
 			DRM_DEBUG_KMS("Format requires non-linear modifier for plane %d\n", i);
 			return -EINVAL;
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index 4201dc1f32a5..e20f4d00b0a5 100644
--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
@@ -21,6 +21,11 @@
 #include <drm/drm_modeset_helper.h>
 #include <drm/drm_simple_kms_helper.h>
 
+#define AFBC_HEADER_SIZE		16
+#define AFBC_TH_LAYOUT_ALIGNMENT	8
+#define AFBC_SUPERBLOCK_PIXELS		256
+#define AFBC_SUPERBLOCK_ALIGNMENT	128
+
 /**
  * DOC: overview
  *
@@ -200,6 +205,40 @@ int drm_gem_fb_lookup(struct drm_device *dev,
 }
 EXPORT_SYMBOL_GPL(drm_gem_fb_lookup);
 
+static int drm_gem_afbc_min_size(struct drm_device *dev,
+				 const struct drm_mode_fb_cmd2 *mode_cmd,
+				 struct drm_afbc *afbc)
+{
+	u32 n_blocks;
+
+	if (!drm_afbc_get_superblock_wh(mode_cmd->modifier[0],
+					&afbc->block_width,
+					&afbc->block_height)) {
+		return -EINVAL;
+	}
+
+	/* tiled header afbc */
+	if (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_TILED) {
+		afbc->block_width *= AFBC_TH_LAYOUT_ALIGNMENT;
+		afbc->block_height *= AFBC_TH_LAYOUT_ALIGNMENT;
+	}
+
+	afbc->aligned_width = ALIGN(mode_cmd->width, afbc->block_width);
+	afbc->aligned_height = ALIGN(mode_cmd->height, afbc->block_height);
+	afbc->offset = mode_cmd->offsets[0];
+
+	n_blocks = (afbc->aligned_width * afbc->aligned_height)
+		 / AFBC_SUPERBLOCK_PIXELS;
+	afbc->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
+				     afbc->alignment_header);
+
+	afbc->afbc_size = afbc->offset_payload + n_blocks *
+			  ALIGN(afbc->bpp * AFBC_SUPERBLOCK_PIXELS / 8,
+				AFBC_SUPERBLOCK_ALIGNMENT);
+
+	return 0;
+}
+
 /**
  * drm_gem_fb_size_check_special() - Helper function for use in
  *				     &drm_mode_config_funcs.fb_create
@@ -218,6 +257,7 @@ int drm_gem_fb_size_check_special(struct drm_device *dev,
 				  const struct drm_size_check *check,
 				  struct drm_gem_object **objs)
 {
+#define CHECK_HAS(field) (check && check->field)
 	const struct drm_format_info *info;
 	int i;
 
@@ -231,24 +271,34 @@ int drm_gem_fb_size_check_special(struct drm_device *dev,
 		unsigned int min_size;
 		u32 pitch = mode_cmd->pitches[i];
 
-		if (check && check->use_pitch_multiplier)
+		if (CHECK_HAS(use_pitch_multiplier))
 			if ((pitch * check->pitch_multiplier[i]) %
 			    check->pitch_modulo)
 				return -EINVAL;
 
-		if (check && check->use_min_size)
+		if (CHECK_HAS(use_min_size)) {
 			min_size = check->min_size[i];
-		else
+		} else if (CHECK_HAS(data) &&
+				drm_is_afbc(mode_cmd->modifier[0])) {
+			struct drm_afbc *afbc;
+			int ret;
+
+			afbc = check->data;
+			ret = drm_gem_afbc_min_size(dev, mode_cmd, afbc);
+			if (ret < 0)
+				return ret;
+			min_size = ret;
+		} else {
 			min_size = (height - 1) * pitch
 				 + drm_format_info_min_pitch(info, i, width)
 				 + mode_cmd->offsets[i];
-
+		}
 		if (objs[i]->size < min_size)
 			return -EINVAL;
 	}
 
 	return 0;
-
+#undef CHECK_HAS
 }
 EXPORT_SYMBOL_GPL(drm_gem_fb_size_check_special);
 
diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h
index 74304a268694..3d6015194b3c 100644
--- a/include/drm/drm_gem_framebuffer_helper.h
+++ b/include/drm/drm_gem_framebuffer_helper.h
@@ -22,6 +22,22 @@ struct drm_size_check {
 	u32 pitch_multiplier[4];
 	u32 pitch_modulo;
 	bool use_pitch_multiplier;
+	void *data;
+};
+
+/**
+ * struct drm_afbc - AFBC-specific data.
+ */
+struct drm_afbc {
+	u32 block_width;
+	u32 block_height;
+	u32 aligned_width;
+	u32 aligned_height;
+	u32 offset;
+	u32 alignment_header;
+	u32 afbc_size;
+	u32 offset_payload;
+	u32 bpp;
 };
 
 struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb,
-- 
2.17.1



More information about the dri-devel mailing list