[PATCH] drm/fb-helper: Redo fb format<->fb_bitfield mapping

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx>

Replace the switch statements that try to map between the fb format and
the fb_bitfield infromation with a single table.

Note that this changes the behaviour of drm_fb_helper_check_var() to
return an error of the requested fb_bitfields don't match the actual
pixel format. Previously we just sort of semi-trusted some of the
bpp/depth information the user was asking for, and never actually
checked if that matches the fb pixel format.

This prepares us to use all different rgb format channel layouts.
Basically would just need some decent way for the driver/cmdline
to select the one you want.

I didn't think about endianness here at all. Not sure how fbdev is
supposed to deal with that stuff anyway, and I don't think we ever
reached a real concensus on the drm fourcc endianness either. So
I'll just pretend everything is little endian and ignore everything
else.

Cc: Linus Walleij <linus.walleij@xxxxxxxxxx>
Cc: Noralf Trønnes <noralf@xxxxxxxxxxx>
Cc: Ilia Mirkin <imirkin@xxxxxxxxxxxx>
Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx>
---
 drivers/gpu/drm/drm_fb_helper.c | 280 +++++++++++++++++++++++-----------------
 1 file changed, 163 insertions(+), 117 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 035784ddd133..0c906e3a5bb1 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -40,6 +40,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
 
 #include "drm_crtc_internal.h"
 #include "drm_crtc_helper_internal.h"
@@ -1561,6 +1562,147 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 }
 EXPORT_SYMBOL(drm_fb_helper_ioctl);
 
+#define FB_FORMAT_C(c) { \
+	.format = DRM_FORMAT_C##c,    \
+	.blue   = { .length = (c), }, \
+	.green  = { .length = (c), }, \
+	.red    = { .length = (c), }, \
+}
+#define FB_FORMAT_RGB(r, g, b) { \
+	.format = DRM_FORMAT_RGB##r##g##b, \
+	.blue   = { .length = (b), .offset = 0, }, \
+	.green  = { .length = (g), .offset = (b), }, \
+	.red    = { .length = (r), .offset = (b)+(g), }, \
+}
+#define FB_FORMAT_BGR(b, g, r) { \
+	.format = DRM_FORMAT_BGR##b##g##r, \
+	.red    = { .length = (r), .offset = 0, }, \
+	.green  = { .length = (g), .offset = (r), }, \
+	.blue   = { .length = (b), .offset = (r)+(g), }, \
+}
+#define FB_FORMAT_XRGB(x, r, g, b) { \
+	.format = DRM_FORMAT_XRGB##x##r##g##b, \
+	.blue   = { .length = (b), .offset = 0, }, \
+	.green  = { .length = (g), .offset = (b), }, \
+	.red    = { .length = (r), .offset = (b)+(g), }, \
+}
+#define FB_FORMAT_XBGR(x, b, g, r) { \
+	.format = DRM_FORMAT_XBGR##x##b##g##r, \
+	.red    = { .length = (r), .offset = 0, }, \
+	.green  = { .length = (g), .offset = (r), }, \
+	.blue   = { .length = (b), .offset = (r)+(g), }, \
+}
+#define FB_FORMAT_RGBX(r, g, b, x) { \
+	.format = DRM_FORMAT_RGBX##r##g##b##x, \
+	.blue   = { .length = (b), .offset = (x), }, \
+	.green  = { .length = (g), .offset = (x)+(b), }, \
+	.red    = { .length = (r), .offset = (x)+(b)+(g), }, \
+}
+#define FB_FORMAT_BGRX(b, g, r, x) { \
+	.format = DRM_FORMAT_BGRX##b##g##r##x, \
+	.red    = { .length = (r), .offset = (x), }, \
+	.green  = { .length = (g), .offset = (x)+(r), }, \
+	.blue   = { .length = (b), .offset = (x)+(r)+(g), }, \
+}
+#define FB_FORMAT_ARGB(a, r, g, b) { \
+	.format = DRM_FORMAT_ARGB##a##r##g##b, \
+	.blue   = { .length = (b), .offset = 0, }, \
+	.green  = { .length = (g), .offset = (b), }, \
+	.red    = { .length = (r), .offset = (b)+(g), }, \
+	.transp = { .length = (a), .offset = (b)+(g)+(r), }, \
+}
+#define FB_FORMAT_ABGR(a, b, g, r) { \
+	.format = DRM_FORMAT_ABGR##a##b##g##r, \
+	.red    = { .length = (r), .offset = 0, }, \
+	.green  = { .length = (g), .offset = (r), }, \
+	.blue   = { .length = (b), .offset = (r)+(g), },\
+	.transp = { .length = (a), .offset = (r)+(g)+(b), }, \
+}
+#define FB_FORMAT_RGBA(r, g, b, a) { \
+	.format = DRM_FORMAT_RGBA##r##g##b##a, \
+	.transp = { .length = (a), .offset = 0, }, \
+	.blue   = { .length = (b), .offset = (a), }, \
+	.green  = { .length = (g), .offset = (a)+(b), }, \
+	.red    = { .length = (r), .offset = (a)+(b)+(g), }, \
+}
+#define FB_FORMAT_BGRA(b, g, r, a) { \
+	.format = DRM_FORMAT_BGRA##b##g##r##a, \
+	.transp = { .length = (a), .offset = 0, }, \
+	.red    = { .length = (r), .offset = (a), }, \
+	.green  = { .length = (g), .offset = (a)+(r), }, \
+	.blue   = { .length = (b), .offset = (a)+(r)+(g), }, \
+}
+
+struct drm_fb_helper_format {
+	u32 format;
+	struct fb_bitfield red, green, blue, transp;
+};
+
+static const struct drm_fb_helper_format fb_formats[] = {
+	FB_FORMAT_C(8),
+
+	FB_FORMAT_XRGB(1, 5, 5, 5),
+	FB_FORMAT_XBGR(1, 5, 5, 5),
+	FB_FORMAT_RGBX(5, 5, 5, 1),
+	FB_FORMAT_BGRX(5, 5, 5, 1),
+
+	FB_FORMAT_ARGB(1, 5, 5, 5),
+	FB_FORMAT_ABGR(1, 5, 5, 5),
+	FB_FORMAT_RGBA(5, 5, 5, 1),
+	FB_FORMAT_BGRA(5, 5, 5, 1),
+
+	FB_FORMAT_RGB(5, 6, 5),
+	FB_FORMAT_BGR(5, 6, 5),
+
+	FB_FORMAT_RGB(8, 8, 8),
+	FB_FORMAT_BGR(8, 8, 8),
+
+	FB_FORMAT_XRGB(8, 8, 8, 8),
+	FB_FORMAT_XBGR(8, 8, 8, 8),
+	FB_FORMAT_RGBX(8, 8, 8, 8),
+	FB_FORMAT_BGRX(8, 8, 8, 8),
+
+	FB_FORMAT_ARGB(8, 8, 8, 8),
+	FB_FORMAT_ABGR(8, 8, 8, 8),
+	FB_FORMAT_RGBA(8, 8, 8, 8),
+	FB_FORMAT_BGRA(8, 8, 8, 8),
+
+	FB_FORMAT_XRGB(2, 10, 10, 10),
+	FB_FORMAT_XBGR(2, 10, 10, 10),
+	FB_FORMAT_RGBX(10, 10, 10, 2),
+	FB_FORMAT_BGRX(10, 10, 10, 2),
+
+	FB_FORMAT_ARGB(2, 10, 10, 10),
+	FB_FORMAT_ABGR(2, 10, 10, 10),
+	FB_FORMAT_RGBA(10, 10, 10, 2),
+	FB_FORMAT_BGRA(10, 10, 10, 2),
+};
+
+static bool fb_format_match(const struct fb_var_screeninfo *var,
+			    const struct drm_fb_helper_format *fb_format)
+{
+	return !memcmp(&var->red, &fb_format->red,
+		       sizeof(var->red)) &&
+		!memcmp(&var->green, &fb_format->green,
+			sizeof(var->green)) &&
+		!memcmp(&var->blue, &fb_format->blue,
+			sizeof(var->blue)) &&
+		!memcmp(&var->transp, &fb_format->transp,
+			sizeof(var->transp));
+}
+
+static const struct drm_fb_helper_format *fb_format_lookup(u32 format)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fb_formats); i++) {
+		if (fb_formats[i].format == format)
+			return &fb_formats[i];
+	}
+
+	return NULL;
+}
+
 /**
  * drm_fb_helper_check_var - implementation for &fb_ops.fb_check_var
  * @var: screeninfo to check
@@ -1569,9 +1711,9 @@ EXPORT_SYMBOL(drm_fb_helper_ioctl);
 int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
 			    struct fb_info *info)
 {
+	const struct drm_fb_helper_format *fb_format;
 	struct drm_fb_helper *fb_helper = info->par;
 	struct drm_framebuffer *fb = fb_helper->fb;
-	int depth;
 
 	if (var->pixclock != 0 || in_dbg_master())
 		return -EINVAL;
@@ -1591,72 +1733,20 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
 		return -EINVAL;
 	}
 
-	switch (var->bits_per_pixel) {
-	case 16:
-		depth = (var->green.length == 6) ? 16 : 15;
-		break;
-	case 32:
-		depth = (var->transp.length > 0) ? 32 : 24;
-		break;
-	default:
-		depth = var->bits_per_pixel;
-		break;
-	}
+	/*
+	 * FIXME just store the fb_bitfields for the
+	 * chosen fb format somewhere to avoid the lookup?
+	 * Or sort the table and use bsearch()?
+	 */
+	fb_format = fb_format_lookup(fb->format->format);
+	if (WARN_ON(!fb_format))
+		return -EINVAL;
 
-	switch (depth) {
-	case 8:
-		var->red.offset = 0;
-		var->green.offset = 0;
-		var->blue.offset = 0;
-		var->red.length = 8;
-		var->green.length = 8;
-		var->blue.length = 8;
-		var->transp.length = 0;
-		var->transp.offset = 0;
-		break;
-	case 15:
-		var->red.offset = 10;
-		var->green.offset = 5;
-		var->blue.offset = 0;
-		var->red.length = 5;
-		var->green.length = 5;
-		var->blue.length = 5;
-		var->transp.length = 1;
-		var->transp.offset = 15;
-		break;
-	case 16:
-		var->red.offset = 11;
-		var->green.offset = 5;
-		var->blue.offset = 0;
-		var->red.length = 5;
-		var->green.length = 6;
-		var->blue.length = 5;
-		var->transp.length = 0;
-		var->transp.offset = 0;
-		break;
-	case 24:
-		var->red.offset = 16;
-		var->green.offset = 8;
-		var->blue.offset = 0;
-		var->red.length = 8;
-		var->green.length = 8;
-		var->blue.length = 8;
-		var->transp.length = 0;
-		var->transp.offset = 0;
-		break;
-	case 32:
-		var->red.offset = 16;
-		var->green.offset = 8;
-		var->blue.offset = 0;
-		var->red.length = 8;
-		var->green.length = 8;
-		var->blue.length = 8;
-		var->transp.length = 8;
-		var->transp.offset = 24;
-		break;
-	default:
+	if (!fb_format_match(var, fb_format)) {
+		DRM_DEBUG_KMS("var screeninfo does not match pixel format\n");
 		return -EINVAL;
 	}
+
 	return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_check_var);
@@ -1948,6 +2038,7 @@ EXPORT_SYMBOL(drm_fb_helper_fill_fix);
 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
 			    uint32_t fb_width, uint32_t fb_height)
 {
+	const struct drm_fb_helper_format *fb_format;
 	struct drm_framebuffer *fb = fb_helper->fb;
 
 	info->pseudo_palette = fb_helper->pseudo_palette;
@@ -1959,59 +2050,14 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
 	info->var.yoffset = 0;
 	info->var.activate = FB_ACTIVATE_NOW;
 
-	switch (fb->format->depth) {
-	case 8:
-		info->var.red.offset = 0;
-		info->var.green.offset = 0;
-		info->var.blue.offset = 0;
-		info->var.red.length = 8; /* 8bit DAC */
-		info->var.green.length = 8;
-		info->var.blue.length = 8;
-		info->var.transp.offset = 0;
-		info->var.transp.length = 0;
-		break;
-	case 15:
-		info->var.red.offset = 10;
-		info->var.green.offset = 5;
-		info->var.blue.offset = 0;
-		info->var.red.length = 5;
-		info->var.green.length = 5;
-		info->var.blue.length = 5;
-		info->var.transp.offset = 15;
-		info->var.transp.length = 1;
-		break;
-	case 16:
-		info->var.red.offset = 11;
-		info->var.green.offset = 5;
-		info->var.blue.offset = 0;
-		info->var.red.length = 5;
-		info->var.green.length = 6;
-		info->var.blue.length = 5;
-		info->var.transp.offset = 0;
-		break;
-	case 24:
-		info->var.red.offset = 16;
-		info->var.green.offset = 8;
-		info->var.blue.offset = 0;
-		info->var.red.length = 8;
-		info->var.green.length = 8;
-		info->var.blue.length = 8;
-		info->var.transp.offset = 0;
-		info->var.transp.length = 0;
-		break;
-	case 32:
-		info->var.red.offset = 16;
-		info->var.green.offset = 8;
-		info->var.blue.offset = 0;
-		info->var.red.length = 8;
-		info->var.green.length = 8;
-		info->var.blue.length = 8;
-		info->var.transp.offset = 24;
-		info->var.transp.length = 8;
-		break;
-	default:
-		break;
-	}
+	fb_format = fb_format_lookup(fb->format->format);
+	if (WARN_ON(!fb_format))
+		return;
+
+	info->var.red = fb_format->red;
+	info->var.green = fb_format->green;
+	info->var.blue = fb_format->blue;
+	info->var.transp = fb_format->transp;
 
 	info->var.xres = fb_width;
 	info->var.yres = fb_height;
-- 
2.13.6

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/dri-devel




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux