[PATCH 4/4] drm/format-helper: Share implementation among conversion helpers

Thomas Zimmermann tzimmermann at suse.de
Wed Apr 27 14:14:09 UTC 2022


Provide format-independent conversion helpers for system and I/O
memory. Implement most existing helpers on top of it. The source and
destination formats of each conversion is handled by a per-line
helper that is given to the generic implementation.

Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
---
 drivers/gpu/drm/drm_format_helper.c | 370 ++++++++++------------------
 1 file changed, 124 insertions(+), 246 deletions(-)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index 21d0d282c6a1..6f8030ebb56d 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -40,6 +40,95 @@ unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info
 }
 EXPORT_SYMBOL(drm_fb_clip_offset);
 
+/* TODO: Make this functon work with multi-plane formats. */
+static int drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
+		       const void *vaddr, const struct drm_framebuffer *fb,
+		       const struct drm_rect *clip, bool vaddr_cached_hint,
+		       void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
+{
+	unsigned long linepixels = drm_rect_width(clip);
+	unsigned long lines = drm_rect_height(clip);
+	size_t sbuf_len = linepixels * fb->format->cpp[0];
+	void *stmp = NULL;
+	unsigned long i;
+	const void *sbuf;
+
+	/*
+	 * Some source buffers, such as CMA memory, use write-combine
+	 * caching, so reads are uncached. Speed up access by fetching
+	 * one line at a time.
+	 */
+	if (!vaddr_cached_hint) {
+		stmp = kmalloc(sbuf_len, GFP_KERNEL);
+		if (!stmp)
+			return -ENOMEM;
+	}
+
+	if (!dst_pitch)
+		dst_pitch = drm_rect_width(clip) * dst_pixsize;
+	vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
+
+	for (i = 0; i < lines; ++i) {
+		if (stmp)
+			sbuf = memcpy(stmp, vaddr, sbuf_len);
+		else
+			sbuf = vaddr;
+		xfrm_line(dst, sbuf, linepixels);
+		vaddr += fb->pitches[0];
+		dst += dst_pitch;
+	}
+
+	kfree(stmp);
+
+	return 0;
+}
+
+/* TODO: Make this functon work with multi-plane formats. */
+static int drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
+			    const void *vaddr, const struct drm_framebuffer *fb,
+			    const struct drm_rect *clip, bool vaddr_cached_hint,
+			    void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
+{
+	unsigned long linepixels = drm_rect_width(clip);
+	unsigned long lines = drm_rect_height(clip);
+	size_t dbuf_len = linepixels * dst_pixsize;
+	size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */
+	size_t sbuf_len = linepixels * fb->format->cpp[0];
+	void *stmp = NULL;
+	unsigned long i;
+	const void *sbuf;
+	void *dbuf;
+
+	if (vaddr_cached_hint) {
+		dbuf = kmalloc(dbuf_len, GFP_KERNEL);
+	} else {
+		dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL);
+		stmp = dbuf + stmp_off;
+	}
+	if (!dbuf)
+		return -ENOMEM;
+
+	if (!dst_pitch)
+		dst_pitch = linepixels * dst_pixsize;
+	vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]);
+
+	for (i = 0; i < lines; ++i) {
+		if (stmp)
+			sbuf = memcpy(stmp, vaddr, sbuf_len);
+		else
+			sbuf = vaddr;
+		xfrm_line(dbuf, sbuf, linepixels);
+		memcpy_toio(dst, dbuf, dbuf_len);
+		vaddr += fb->pitches[0];
+		dst += dst_pitch;
+	}
+
+	kfree(dbuf);
+
+	return 0;
+}
+
+
 /**
  * drm_fb_memcpy - Copy clip buffer
  * @dst: Destination buffer
@@ -140,45 +229,23 @@ void drm_fb_swab(void *dst, unsigned int dst_pitch, const void *src,
 		 bool cached)
 {
 	u8 cpp = fb->format->cpp[0];
-	unsigned long linepixels = drm_rect_width(clip);
-	size_t len = linepixels * cpp;
-	const void *sbuf;
-	void *dbuf;
-	unsigned int y;
-	void *buf = NULL;
-
-	if (WARN_ON_ONCE(cpp != 2 && cpp != 4))
-		return;
-
-	if (!dst_pitch)
-		dst_pitch = len;
-	src += clip_offset(clip, fb->pitches[0], cpp);
-
-	if (!cached)
-		buf = kmalloc(len, GFP_KERNEL);
 
-	for (y = clip->y1; y < clip->y2; y++) {
-		if (buf)
-			sbuf = memcpy(buf, src, len);
-		else
-			sbuf = src;
-		dbuf = dst + clip->x1 * cpp;
-
-		if (cpp == 4)
-			drm_fb_swab32_line(dbuf, sbuf, linepixels);
-		else
-			drm_fb_swab16_line(dbuf, sbuf, linepixels);
-
-		src += fb->pitches[0];
-		dst += dst_pitch;
+	switch (cpp) {
+	case 4:
+		drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab32_line);
+		break;
+	case 2:
+		drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab16_line);
+		break;
+	default:
+		drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n",
+			      &fb->format->format);
+		break;
 	}
-
-	kfree(buf);
 }
 EXPORT_SYMBOL(drm_fb_swab);
 
-static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels,
-					   bool swab)
+static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
 {
 	u8 *dbuf8 = dbuf;
 	const __le32 *sbuf32 = sbuf;
@@ -206,28 +273,7 @@ static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigne
 void drm_fb_xrgb8888_to_rgb332(void *dst, unsigned int dst_pitch, const void *src,
 			       const struct drm_framebuffer *fb, const struct drm_rect *clip)
 {
-	size_t width = drm_rect_width(clip);
-	size_t src_len = width * sizeof(u32);
-	unsigned int y;
-	void *sbuf;
-
-	if (!dst_pitch)
-		dst_pitch = width;
-
-	/* Use a buffer to speed up access on buffers with uncached read mapping (i.e. WC) */
-	sbuf = kmalloc(src_len, GFP_KERNEL);
-	if (!sbuf)
-		return;
-
-	src += clip_offset(clip, fb->pitches[0], sizeof(u32));
-	for (y = 0; y < drm_rect_height(clip); y++) {
-		memcpy(sbuf, src, src_len);
-		drm_fb_xrgb8888_to_rgb332_line(dst, sbuf, width, false);
-		src += fb->pitches[0];
-		dst += dst_pitch;
-	}
-
-	kfree(sbuf);
+	drm_fb_xfrm(dst, dst_pitch, 1, src, fb, clip, false, drm_fb_xrgb8888_to_rgb332_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);
 
@@ -278,35 +324,12 @@ void drm_fb_xrgb8888_to_rgb565(void *dst, unsigned int dst_pitch, const void *va
 			       const struct drm_framebuffer *fb, const struct drm_rect *clip,
 			       bool swab)
 {
-	size_t linepixels = clip->x2 - clip->x1;
-	size_t src_len = linepixels * sizeof(u32);
-	size_t dst_len = linepixels * sizeof(u16);
-	unsigned y, lines = clip->y2 - clip->y1;
-	void *sbuf;
-
-	if (!dst_pitch)
-		dst_pitch = dst_len;
-
-	/*
-	 * The cma memory is write-combined so reads are uncached.
-	 * Speed up by fetching one line at a time.
-	 */
-	sbuf = kmalloc(src_len, GFP_KERNEL);
-	if (!sbuf)
-		return;
-
-	vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
-	for (y = 0; y < lines; y++) {
-		memcpy(sbuf, vaddr, src_len);
-		if (swab)
-			drm_fb_xrgb8888_to_rgb565_swab_line(dst, sbuf, linepixels);
-		else
-			drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels);
-		vaddr += fb->pitches[0];
-		dst += dst_pitch;
-	}
-
-	kfree(sbuf);
+	if (swab)
+		drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false,
+			    drm_fb_xrgb8888_to_rgb565_swab_line);
+	else
+		drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false,
+			    drm_fb_xrgb8888_to_rgb565_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
 
@@ -326,30 +349,12 @@ void drm_fb_xrgb8888_to_rgb565_toio(void __iomem *dst, unsigned int dst_pitch,
 				    const void *vaddr, const struct drm_framebuffer *fb,
 				    const struct drm_rect *clip, bool swab)
 {
-	size_t linepixels = clip->x2 - clip->x1;
-	size_t dst_len = linepixels * sizeof(u16);
-	unsigned y, lines = clip->y2 - clip->y1;
-	void *dbuf;
-
-	if (!dst_pitch)
-		dst_pitch = dst_len;
-
-	dbuf = kmalloc(dst_len, GFP_KERNEL);
-	if (!dbuf)
-		return;
-
-	vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
-	for (y = 0; y < lines; y++) {
-		if (swab)
-			drm_fb_xrgb8888_to_rgb565_swab_line(dbuf, vaddr, linepixels);
-		else
-			drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels);
-		memcpy_toio(dst, dbuf, dst_len);
-		vaddr += fb->pitches[0];
-		dst += dst_pitch;
-	}
-
-	kfree(dbuf);
+	if (swab)
+		drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false,
+				 drm_fb_xrgb8888_to_rgb565_swab_line);
+	else
+		drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false,
+				 drm_fb_xrgb8888_to_rgb565_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_toio);
 
@@ -380,28 +385,7 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne
 void drm_fb_xrgb8888_to_rgb888(void *dst, unsigned int dst_pitch, const void *src,
 			       const struct drm_framebuffer *fb, const struct drm_rect *clip)
 {
-	size_t width = drm_rect_width(clip);
-	size_t src_len = width * sizeof(u32);
-	unsigned int y;
-	void *sbuf;
-
-	if (!dst_pitch)
-		dst_pitch = width * 3;
-
-	/* Use a buffer to speed up access on buffers with uncached read mapping (i.e. WC) */
-	sbuf = kmalloc(src_len, GFP_KERNEL);
-	if (!sbuf)
-		return;
-
-	src += clip_offset(clip, fb->pitches[0], sizeof(u32));
-	for (y = 0; y < drm_rect_height(clip); y++) {
-		memcpy(sbuf, src, src_len);
-		drm_fb_xrgb8888_to_rgb888_line(dst, sbuf, width);
-		src += fb->pitches[0];
-		dst += dst_pitch;
-	}
-
-	kfree(sbuf);
+	drm_fb_xfrm(dst, dst_pitch, 3, src, fb, clip, false, drm_fb_xrgb8888_to_rgb888_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
 
@@ -420,27 +404,8 @@ void drm_fb_xrgb8888_to_rgb888_toio(void __iomem *dst, unsigned int dst_pitch,
 				    const void *vaddr, const struct drm_framebuffer *fb,
 				    const struct drm_rect *clip)
 {
-	size_t linepixels = clip->x2 - clip->x1;
-	size_t dst_len = linepixels * 3;
-	unsigned y, lines = clip->y2 - clip->y1;
-	void *dbuf;
-
-	if (!dst_pitch)
-		dst_pitch = dst_len;
-
-	dbuf = kmalloc(dst_len, GFP_KERNEL);
-	if (!dbuf)
-		return;
-
-	vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
-	for (y = 0; y < lines; y++) {
-		drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels);
-		memcpy_toio(dst, dbuf, dst_len);
-		vaddr += fb->pitches[0];
-		dst += dst_pitch;
-	}
-
-	kfree(dbuf);
+	drm_fb_xfrm_toio(dst, dst_pitch, 3, vaddr, fb, clip, false,
+			 drm_fb_xrgb8888_to_rgb888_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_toio);
 
@@ -464,27 +429,8 @@ static void drm_fb_rgb565_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_p
 					   const void *vaddr, const struct drm_framebuffer *fb,
 					   const struct drm_rect *clip)
 {
-	size_t linepixels = drm_rect_width(clip);
-	size_t dst_len = linepixels * 4;
-	unsigned int y, lines = drm_rect_height(clip);
-	void *dbuf;
-
-	if (!dst_pitch)
-		dst_pitch = dst_len;
-
-	dbuf = kmalloc(dst_len, GFP_KERNEL);
-	if (!dbuf)
-		return;
-
-	vaddr += clip_offset(clip, fb->pitches[0], 2);
-	for (y = 0; y < lines; y++) {
-		drm_fb_rgb565_to_xrgb8888_line(dbuf, vaddr, linepixels);
-		memcpy_toio(dst, dbuf, dst_len);
-		vaddr += fb->pitches[0];
-		dst += dst_pitch;
-	}
-
-	kfree(dbuf);
+	drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false,
+			 drm_fb_rgb565_to_xrgb8888_line);
 }
 
 static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
@@ -505,27 +451,8 @@ static void drm_fb_rgb888_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_p
 					   const void *vaddr, const struct drm_framebuffer *fb,
 					   const struct drm_rect *clip)
 {
-	size_t linepixels = drm_rect_width(clip);
-	size_t dst_len = linepixels * 4;
-	unsigned int y, lines = drm_rect_height(clip);
-	void *dbuf;
-
-	if (!dst_pitch)
-		dst_pitch = dst_len;
-
-	dbuf = kmalloc(dst_len, GFP_KERNEL);
-	if (!dbuf)
-		return;
-
-	vaddr += clip_offset(clip, fb->pitches[0], 3);
-	for (y = 0; y < lines; y++) {
-		drm_fb_rgb888_to_xrgb8888_line(dbuf, vaddr, linepixels);
-		memcpy_toio(dst, dbuf, dst_len);
-		vaddr += fb->pitches[0];
-		dst += dst_pitch;
-	}
-
-	kfree(dbuf);
+	drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false,
+			 drm_fb_rgb888_to_xrgb8888_line);
 }
 
 static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
@@ -560,27 +487,8 @@ void drm_fb_xrgb8888_to_xrgb2101010_toio(void __iomem *dst,
 					 const struct drm_framebuffer *fb,
 					 const struct drm_rect *clip)
 {
-	size_t linepixels = clip->x2 - clip->x1;
-	size_t dst_len = linepixels * sizeof(u32);
-	unsigned int y, lines = clip->y2 - clip->y1;
-	void *dbuf;
-
-	if (!dst_pitch)
-		dst_pitch = dst_len;
-
-	dbuf = kmalloc(dst_len, GFP_KERNEL);
-	if (!dbuf)
-		return;
-
-	vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
-	for (y = 0; y < lines; y++) {
-		drm_fb_xrgb8888_to_xrgb2101010_line(dbuf, vaddr, linepixels);
-		memcpy_toio(dst, dbuf, dst_len);
-		vaddr += fb->pitches[0];
-		dst += dst_pitch;
-	}
-
-	kfree(dbuf);
+	drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false,
+			 drm_fb_xrgb8888_to_xrgb2101010_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio);
 
@@ -621,37 +529,7 @@ static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned
 void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vaddr,
 			      const struct drm_framebuffer *fb, const struct drm_rect *clip)
 {
-	unsigned int linepixels = clip->x2 - clip->x1;
-	unsigned int len = linepixels * sizeof(u32);
-	unsigned int y;
-	void *buf;
-	u8 *dst8;
-	u32 *src32;
-
-	if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
-		return;
-
-	if (!dst_pitch)
-		dst_pitch = drm_rect_width(clip);
-
-	/*
-	 * The cma memory is write-combined so reads are uncached.
-	 * Speed up by fetching one line at a time.
-	 */
-	buf = kmalloc(len, GFP_KERNEL);
-	if (!buf)
-		return;
-
-	vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32));
-	for (y = clip->y1; y < clip->y2; y++) {
-		dst8 = dst;
-		src32 = memcpy(buf, vaddr, len);
-		drm_fb_xrgb8888_to_gray8_line(dst8, src32, linepixels);
-		vaddr += fb->pitches[0];
-		dst += dst_pitch;
-	}
-
-	kfree(buf);
+	drm_fb_xfrm(dst, dst_pitch, 1, vaddr, fb, clip, false, drm_fb_xrgb8888_to_gray8_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
 
-- 
2.36.0



More information about the dri-devel mailing list