diff options
Diffstat (limited to 'drivers/gpu/drm/drm_format_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_format_helper.c | 679 |
1 files changed, 304 insertions, 375 deletions
diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index 01d3ab307ac3..8f3daf38ca63 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -8,6 +8,7 @@ * (at your option) any later version. */ +#include <linux/export.h> #include <linux/io.h> #include <linux/iosys-map.h> #include <linux/module.h> @@ -20,6 +21,8 @@ #include <drm/drm_print.h> #include <drm/drm_rect.h> +#include "drm_format_internal.h" + /** * drm_format_conv_state_init - Initialize format-conversion state * @state: The state to initialize @@ -244,6 +247,152 @@ static int drm_fb_xfrm(struct iosys_map *dst, xfrm_line); } +#define ALIGN_DOWN_PIXELS(end, n, a) \ + ((end) - ((n) & ((a) - 1))) + +static __always_inline void drm_fb_xfrm_line_32to8(void *dbuf, const void *sbuf, + unsigned int pixels, + u32 (*xfrm_pixel)(u32)) +{ + __le32 *dbuf32 = dbuf; + u8 *dbuf8; + const __le32 *sbuf32 = sbuf; + const __le32 *send32 = sbuf32 + pixels; + + /* write 4 pixels at once */ + while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 4)) { + u32 pix[4] = { + le32_to_cpup(sbuf32), + le32_to_cpup(sbuf32 + 1), + le32_to_cpup(sbuf32 + 2), + le32_to_cpup(sbuf32 + 3), + }; + /* write output bytes in reverse order for little endianness */ + u32 val32 = xfrm_pixel(pix[0]) | + (xfrm_pixel(pix[1]) << 8) | + (xfrm_pixel(pix[2]) << 16) | + (xfrm_pixel(pix[3]) << 24); + *dbuf32++ = cpu_to_le32(val32); + sbuf32 += ARRAY_SIZE(pix); + } + + /* write trailing pixels */ + dbuf8 = (u8 __force *)dbuf32; + while (sbuf32 < send32) + *dbuf8++ = xfrm_pixel(le32_to_cpup(sbuf32++)); +} + +static __always_inline void drm_fb_xfrm_line_32to16(void *dbuf, const void *sbuf, + unsigned int pixels, + u32 (*xfrm_pixel)(u32)) +{ + __le64 *dbuf64 = dbuf; + __le32 *dbuf32; + __le16 *dbuf16; + const __le32 *sbuf32 = sbuf; + const __le32 *send32 = sbuf32 + pixels; + +#if defined(CONFIG_64BIT) + /* write 4 pixels at once */ + while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 4)) { + u32 pix[4] = { + le32_to_cpup(sbuf32), + le32_to_cpup(sbuf32 + 1), + le32_to_cpup(sbuf32 + 2), + le32_to_cpup(sbuf32 + 3), + }; + /* write output bytes in reverse order for little endianness */ + u64 val64 = ((u64)xfrm_pixel(pix[0])) | + ((u64)xfrm_pixel(pix[1]) << 16) | + ((u64)xfrm_pixel(pix[2]) << 32) | + ((u64)xfrm_pixel(pix[3]) << 48); + *dbuf64++ = cpu_to_le64(val64); + sbuf32 += ARRAY_SIZE(pix); + } +#endif + + /* write 2 pixels at once */ + dbuf32 = (__le32 __force *)dbuf64; + while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 2)) { + u32 pix[2] = { + le32_to_cpup(sbuf32), + le32_to_cpup(sbuf32 + 1), + }; + /* write output bytes in reverse order for little endianness */ + u32 val32 = xfrm_pixel(pix[0]) | + (xfrm_pixel(pix[1]) << 16); + *dbuf32++ = cpu_to_le32(val32); + sbuf32 += ARRAY_SIZE(pix); + } + + /* write trailing pixel */ + dbuf16 = (__le16 __force *)dbuf32; + while (sbuf32 < send32) + *dbuf16++ = cpu_to_le16(xfrm_pixel(le32_to_cpup(sbuf32++))); +} + +static __always_inline void drm_fb_xfrm_line_32to24(void *dbuf, const void *sbuf, + unsigned int pixels, + u32 (*xfrm_pixel)(u32)) +{ + __le32 *dbuf32 = dbuf; + u8 *dbuf8; + const __le32 *sbuf32 = sbuf; + const __le32 *send32 = sbuf32 + pixels; + + /* write pixels in chunks of 4 */ + while (sbuf32 < ALIGN_DOWN_PIXELS(send32, pixels, 4)) { + u32 val24[4] = { + xfrm_pixel(le32_to_cpup(sbuf32)), + xfrm_pixel(le32_to_cpup(sbuf32 + 1)), + xfrm_pixel(le32_to_cpup(sbuf32 + 2)), + xfrm_pixel(le32_to_cpup(sbuf32 + 3)), + }; + u32 out32[3] = { + /* write output bytes in reverse order for little endianness */ + ((val24[0] & 0x000000ff)) | + ((val24[0] & 0x0000ff00)) | + ((val24[0] & 0x00ff0000)) | + ((val24[1] & 0x000000ff) << 24), + ((val24[1] & 0x0000ff00) >> 8) | + ((val24[1] & 0x00ff0000) >> 8) | + ((val24[2] & 0x000000ff) << 16) | + ((val24[2] & 0x0000ff00) << 16), + ((val24[2] & 0x00ff0000) >> 16) | + ((val24[3] & 0x000000ff) << 8) | + ((val24[3] & 0x0000ff00) << 8) | + ((val24[3] & 0x00ff0000) << 8), + }; + + *dbuf32++ = cpu_to_le32(out32[0]); + *dbuf32++ = cpu_to_le32(out32[1]); + *dbuf32++ = cpu_to_le32(out32[2]); + sbuf32 += ARRAY_SIZE(val24); + } + + /* write trailing pixel */ + dbuf8 = (u8 __force *)dbuf32; + while (sbuf32 < send32) { + u32 val24 = xfrm_pixel(le32_to_cpup(sbuf32++)); + /* write output in reverse order for little endianness */ + *dbuf8++ = (val24 & 0x000000ff); + *dbuf8++ = (val24 & 0x0000ff00) >> 8; + *dbuf8++ = (val24 & 0x00ff0000) >> 16; + } +} + +static __always_inline void drm_fb_xfrm_line_32to32(void *dbuf, const void *sbuf, + unsigned int pixels, + u32 (*xfrm_pixel)(u32)) +{ + __le32 *dbuf32 = dbuf; + const __le32 *sbuf32 = sbuf; + const __le32 *send32 = sbuf32 + pixels; + + while (sbuf32 < send32) + *dbuf32++ = cpu_to_le32(xfrm_pixel(le32_to_cpup(sbuf32++))); +} + /** * drm_fb_memcpy - Copy clip buffer * @dst: Array of destination buffers @@ -368,17 +517,7 @@ EXPORT_SYMBOL(drm_fb_swab); static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels) { - u8 *dbuf8 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - dbuf8[x] = ((pix & 0x00e00000) >> 16) | - ((pix & 0x0000e000) >> 11) | - ((pix & 0x000000c0) >> 6); - } + drm_fb_xfrm_line_32to8(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb332); } /** @@ -417,38 +556,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels) { - __le16 *dbuf16 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u16 val16; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - val16 = ((pix & 0x00F80000) >> 8) | - ((pix & 0x0000FC00) >> 5) | - ((pix & 0x000000F8) >> 3); - dbuf16[x] = cpu_to_le16(val16); - } -} - -/* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */ -static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, - unsigned int pixels) -{ - __le16 *dbuf16 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u16 val16; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - val16 = ((pix & 0x00F80000) >> 8) | - ((pix & 0x0000FC00) >> 5) | - ((pix & 0x000000F8) >> 3); - dbuf16[x] = cpu_to_le16(swab16(val16)); - } + drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb565); } /** @@ -460,7 +568,6 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * @state: Transform and conversion state - * @swab: Swap bytes * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -475,39 +582,60 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, */ void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip, struct drm_format_conv_state *state, - bool swab) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 2, }; - void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels); + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, + drm_fb_xrgb8888_to_rgb565_line); +} +EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); - if (swab) - xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line; - else - xfrm_line = drm_fb_xrgb8888_to_rgb565_line; +static void drm_fb_xrgb8888_to_rgb565be_line(void *dbuf, const void *sbuf, + unsigned int pixels) +{ + drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb565be); +} - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, xfrm_line); +/** + * drm_fb_xrgb8888_to_rgb565be - Convert XRGB8888 to RGB565|DRM_FORMAT_BIG_ENDIAN clip buffer + * @dst: Array of RGB565BE destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffer + * @fb: DRM framebuffer + * @clip: Clip rectangle area to copy + * @state: Transform and conversion state + * + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. Destination and framebuffer formats must match. The + * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at + * least as many entries as there are planes in @fb's format. Each entry stores the + * value for the format's respective color plane at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). + * + * Drivers can use this function for RGB565BE devices that don't support XRGB8888 natively. + */ +void drm_fb_xrgb8888_to_rgb565be(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip, struct drm_format_conv_state *state) +{ + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { + 2, + }; + + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, + drm_fb_xrgb8888_to_rgb565be_line); } -EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); +EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565be); static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels) { - __le16 *dbuf16 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u16 val16; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - val16 = ((pix & 0x00f80000) >> 9) | - ((pix & 0x0000f800) >> 6) | - ((pix & 0x000000f8) >> 3); - dbuf16[x] = cpu_to_le16(val16); - } + drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xrgb1555); } /** @@ -547,20 +675,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555); static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsigned int pixels) { - __le16 *dbuf16 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u16 val16; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - val16 = BIT(15) | /* set alpha bit */ - ((pix & 0x00f80000) >> 9) | - ((pix & 0x0000f800) >> 6) | - ((pix & 0x000000f8) >> 3); - dbuf16[x] = cpu_to_le16(val16); - } + drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_argb1555); } /** @@ -600,20 +715,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555); static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsigned int pixels) { - __le16 *dbuf16 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u16 val16; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - val16 = ((pix & 0x00f80000) >> 8) | - ((pix & 0x0000f800) >> 5) | - ((pix & 0x000000f8) >> 2) | - BIT(0); /* set alpha bit */ - dbuf16[x] = cpu_to_le16(val16); - } + drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgba5551); } /** @@ -653,18 +755,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551); static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels) { - u8 *dbuf8 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - /* write blue-green-red to output in little endianness */ - *dbuf8++ = (pix & 0x000000FF) >> 0; - *dbuf8++ = (pix & 0x0000FF00) >> 8; - *dbuf8++ = (pix & 0x00FF0000) >> 16; - } + drm_fb_xfrm_line_32to24(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb888); } /** @@ -704,18 +795,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); static void drm_fb_xrgb8888_to_bgr888_line(void *dbuf, const void *sbuf, unsigned int pixels) { - u8 *dbuf8 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - /* write red-green-blue to output in little endianness */ - *dbuf8++ = (pix & 0x00ff0000) >> 16; - *dbuf8++ = (pix & 0x0000ff00) >> 8; - *dbuf8++ = (pix & 0x000000ff) >> 0; - } + drm_fb_xfrm_line_32to24(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_bgr888); } /** @@ -755,16 +835,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_bgr888); static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) { - __le32 *dbuf32 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - pix |= GENMASK(31, 24); /* fill alpha bits */ - dbuf32[x] = cpu_to_le32(pix); - } + drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_argb8888); } /** @@ -804,26 +875,36 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888); static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels) { - __le32 *dbuf32 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - pix = ((pix & 0x00ff0000) >> 16) << 0 | - ((pix & 0x0000ff00) >> 8) << 8 | - ((pix & 0x000000ff) >> 0) << 16 | - GENMASK(31, 24); /* fill alpha bits */ - *dbuf32++ = cpu_to_le32(pix); - } + drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_abgr8888); } -static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch, - const struct iosys_map *src, - const struct drm_framebuffer *fb, - const struct drm_rect *clip, - struct drm_format_conv_state *state) +/** + * drm_fb_xrgb8888_to_abgr8888 - Convert XRGB8888 to ABGR8888 clip buffer + * @dst: Array of ABGR8888 destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffer + * @fb: DRM framebuffer + * @clip: Clip rectangle area to copy + * @state: Transform and conversion state + * + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. The parameters @dst, @dst_pitch and @src refer + * to arrays. Each array must have at least as many entries as there are planes in + * @fb's format. Each entry stores the value for the format's respective color plane + * at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). + * + * Drivers can use this function for ABGR8888 devices that don't support XRGB8888 + * natively. It sets an opaque alpha channel as part of the conversion. + */ +void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, + const struct drm_framebuffer *fb, + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, @@ -832,29 +913,40 @@ static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned in drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_abgr8888_line); } +EXPORT_SYMBOL(drm_fb_xrgb8888_to_abgr8888); static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels) { - __le32 *dbuf32 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - pix = ((pix & 0x00ff0000) >> 16) << 0 | - ((pix & 0x0000ff00) >> 8) << 8 | - ((pix & 0x000000ff) >> 0) << 16 | - ((pix & 0xff000000) >> 24) << 24; - *dbuf32++ = cpu_to_le32(pix); - } + drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xbgr8888); } -static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch, - const struct iosys_map *src, - const struct drm_framebuffer *fb, - const struct drm_rect *clip, - struct drm_format_conv_state *state) +/** + * drm_fb_xrgb8888_to_xbgr8888 - Convert XRGB8888 to XBGR8888 clip buffer + * @dst: Array of XBGR8888 destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffer + * @fb: DRM framebuffer + * @clip: Clip rectangle area to copy + * @state: Transform and conversion state + * + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. The parameters @dst, @dst_pitch and @src refer + * to arrays. Each array must have at least as many entries as there are planes in + * @fb's format. Each entry stores the value for the format's respective color plane + * at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). + * + * Drivers can use this function for XBGR8888 devices that don't support XRGB8888 + * natively. + */ +void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, + const struct drm_framebuffer *fb, + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, @@ -863,23 +955,53 @@ static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned in drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_xbgr8888_line); } +EXPORT_SYMBOL(drm_fb_xrgb8888_to_xbgr8888); + +static void drm_fb_xrgb8888_to_bgrx8888_line(void *dbuf, const void *sbuf, unsigned int pixels) +{ + drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_bgrx8888); +} + +/** + * drm_fb_xrgb8888_to_bgrx8888 - Convert XRGB8888 to BGRX8888 clip buffer + * @dst: Array of BGRX8888 destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffer + * @fb: DRM framebuffer + * @clip: Clip rectangle area to copy + * @state: Transform and conversion state + * + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. The parameters @dst, @dst_pitch and @src refer + * to arrays. Each array must have at least as many entries as there are planes in + * @fb's format. Each entry stores the value for the format's respective color plane + * at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). + * + * Drivers can use this function for BGRX8888 devices that don't support XRGB8888 + * natively. + */ +void drm_fb_xrgb8888_to_bgrx8888(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, + const struct drm_framebuffer *fb, + const struct drm_rect *clip, + struct drm_format_conv_state *state) +{ + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { + 4, + }; + + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, + drm_fb_xrgb8888_to_bgrx8888_line); +} +EXPORT_SYMBOL(drm_fb_xrgb8888_to_bgrx8888); static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) { - __le32 *dbuf32 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u32 val32; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - val32 = ((pix & 0x000000FF) << 2) | - ((pix & 0x0000FF00) << 4) | - ((pix & 0x00FF0000) << 6); - pix = val32 | ((val32 >> 8) & 0x00300C03); - *dbuf32++ = cpu_to_le32(pix); - } + drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xrgb2101010); } /** @@ -920,21 +1042,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010); static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) { - __le32 *dbuf32 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - u32 val32; - u32 pix; - - for (x = 0; x < pixels; x++) { - pix = le32_to_cpu(sbuf32[x]); - val32 = ((pix & 0x000000ff) << 2) | - ((pix & 0x0000ff00) << 4) | - ((pix & 0x00ff0000) << 6); - pix = GENMASK(31, 30) | /* set alpha bits */ - val32 | ((val32 >> 8) & 0x00300c03); - *dbuf32++ = cpu_to_le32(pix); - } + drm_fb_xfrm_line_32to32(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_argb2101010); } /** @@ -975,19 +1083,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010); static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels) { - u8 *dbuf8 = dbuf; - const __le32 *sbuf32 = sbuf; - unsigned int x; - - for (x = 0; x < pixels; x++) { - u32 pix = le32_to_cpu(sbuf32[x]); - u8 r = (pix & 0x00ff0000) >> 16; - u8 g = (pix & 0x0000ff00) >> 8; - u8 b = pix & 0x000000ff; - - /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */ - *dbuf8++ = (3 * r + 6 * g + b) / 10; - } + drm_fb_xfrm_line_32to8(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_r8_bt601); } /** @@ -1031,36 +1127,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); static void drm_fb_argb8888_to_argb4444_line(void *dbuf, const void *sbuf, unsigned int pixels) { - unsigned int pixels2 = pixels & ~GENMASK_ULL(0, 0); - __le32 *dbuf32 = dbuf; - __le16 *dbuf16 = dbuf + pixels2 * sizeof(*dbuf16); - const __le32 *sbuf32 = sbuf; - unsigned int x; - u32 val32; - u16 val16; - u32 pix[2]; - - for (x = 0; x < pixels2; x += 2, ++dbuf32) { - pix[0] = le32_to_cpu(sbuf32[x]); - pix[1] = le32_to_cpu(sbuf32[x + 1]); - val32 = ((pix[0] & 0xf0000000) >> 16) | - ((pix[0] & 0x00f00000) >> 12) | - ((pix[0] & 0x0000f000) >> 8) | - ((pix[0] & 0x000000f0) >> 4) | - ((pix[1] & 0xf0000000) >> 0) | - ((pix[1] & 0x00f00000) << 4) | - ((pix[1] & 0x0000f000) << 8) | - ((pix[1] & 0x000000f0) << 12); - *dbuf32 = cpu_to_le32(val32); - } - for (; x < pixels; x++) { - pix[0] = le32_to_cpu(sbuf32[x]); - val16 = ((pix[0] & 0xf0000000) >> 16) | - ((pix[0] & 0x00f00000) >> 12) | - ((pix[0] & 0x0000f000) >> 8) | - ((pix[0] & 0x000000f0) >> 4); - dbuf16[x] = cpu_to_le16(val16); - } + drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_argb8888_to_argb4444); } /** @@ -1141,7 +1208,7 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d return 0; } else if (fb_format == DRM_FORMAT_XRGB8888) { if (dst_format == DRM_FORMAT_RGB565) { - drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state, false); + drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_XRGB1555) { drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, state); @@ -1292,141 +1359,3 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc } } EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono); - -static uint32_t drm_fb_nonalpha_fourcc(uint32_t fourcc) -{ - /* only handle formats with depth != 0 and alpha channel */ - switch (fourcc) { - case DRM_FORMAT_ARGB1555: - return DRM_FORMAT_XRGB1555; - case DRM_FORMAT_ABGR1555: - return DRM_FORMAT_XBGR1555; - case DRM_FORMAT_RGBA5551: - return DRM_FORMAT_RGBX5551; - case DRM_FORMAT_BGRA5551: - return DRM_FORMAT_BGRX5551; - case DRM_FORMAT_ARGB8888: - return DRM_FORMAT_XRGB8888; - case DRM_FORMAT_ABGR8888: - return DRM_FORMAT_XBGR8888; - case DRM_FORMAT_RGBA8888: - return DRM_FORMAT_RGBX8888; - case DRM_FORMAT_BGRA8888: - return DRM_FORMAT_BGRX8888; - case DRM_FORMAT_ARGB2101010: - return DRM_FORMAT_XRGB2101010; - case DRM_FORMAT_ABGR2101010: - return DRM_FORMAT_XBGR2101010; - case DRM_FORMAT_RGBA1010102: - return DRM_FORMAT_RGBX1010102; - case DRM_FORMAT_BGRA1010102: - return DRM_FORMAT_BGRX1010102; - } - - return fourcc; -} - -static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc) -{ - const uint32_t *fourccs_end = fourccs + nfourccs; - - while (fourccs < fourccs_end) { - if (*fourccs == fourcc) - return true; - ++fourccs; - } - return false; -} - -/** - * drm_fb_build_fourcc_list - Filters a list of supported color formats against - * the device's native formats - * @dev: DRM device - * @native_fourccs: 4CC codes of natively supported color formats - * @native_nfourccs: The number of entries in @native_fourccs - * @fourccs_out: Returns 4CC codes of supported color formats - * @nfourccs_out: The number of available entries in @fourccs_out - * - * This function create a list of supported color format from natively - * supported formats and additional emulated formats. - * At a minimum, most userspace programs expect at least support for - * XRGB8888 on the primary plane. Devices that have to emulate the - * format, and possibly others, can use drm_fb_build_fourcc_list() to - * create a list of supported color formats. The returned list can - * be handed over to drm_universal_plane_init() et al. Native formats - * will go before emulated formats. Native formats with alpha channel - * will be replaced by such without, as primary planes usually don't - * support alpha. Other heuristics might be applied - * to optimize the order. Formats near the beginning of the list are - * usually preferred over formats near the end of the list. - * - * Returns: - * The number of color-formats 4CC codes returned in @fourccs_out. - */ -size_t drm_fb_build_fourcc_list(struct drm_device *dev, - const u32 *native_fourccs, size_t native_nfourccs, - u32 *fourccs_out, size_t nfourccs_out) -{ - /* - * XRGB8888 is the default fallback format for most of userspace - * and it's currently the only format that should be emulated for - * the primary plane. Only if there's ever another default fallback, - * it should be added here. - */ - static const uint32_t extra_fourccs[] = { - DRM_FORMAT_XRGB8888, - }; - static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs); - - u32 *fourccs = fourccs_out; - const u32 *fourccs_end = fourccs_out + nfourccs_out; - size_t i; - - /* - * The device's native formats go first. - */ - - for (i = 0; i < native_nfourccs; ++i) { - /* - * Several DTs, boot loaders and firmware report native - * alpha formats that are non-alpha formats instead. So - * replace alpha formats by non-alpha formats. - */ - u32 fourcc = drm_fb_nonalpha_fourcc(native_fourccs[i]); - - if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { - continue; /* skip duplicate entries */ - } else if (fourccs == fourccs_end) { - drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc); - continue; /* end of available output buffer */ - } - - drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc); - - *fourccs = fourcc; - ++fourccs; - } - - /* - * The extra formats, emulated by the driver, go second. - */ - - for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) { - u32 fourcc = extra_fourccs[i]; - - if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { - continue; /* skip duplicate and native entries */ - } else if (fourccs == fourccs_end) { - drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc); - continue; /* end of available output buffer */ - } - - drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc); - - *fourccs = fourcc; - ++fourccs; - } - - return fourccs - fourccs_out; -} -EXPORT_SYMBOL(drm_fb_build_fourcc_list); |