Commit cce6bedb authored by Thomas Zimmermann's avatar Thomas Zimmermann
Browse files

drm/format-helper: Share implementation among conversion helpers



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.

v2:
	* remove a blank line

Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarJavier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220427141409.22842-5-tzimmermann@suse.de
parent a6fdb669
Loading
Loading
Loading
Loading
+123 −246
Original line number Diff line number Diff line
@@ -40,6 +40,94 @@ 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 +228,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 +272,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 +323,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);
		drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false,
			    drm_fb_xrgb8888_to_rgb565_swab_line);
	else
			drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels);
		vaddr += fb->pitches[0];
		dst += dst_pitch;
	}

	kfree(sbuf);
		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 +348,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);
		drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false,
				 drm_fb_xrgb8888_to_rgb565_swab_line);
	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);
		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 +384,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 +403,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 +428,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 +450,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 +486,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 +528,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);