Date: Fri, 20 Feb 1998 12:21:50 GMT
From: Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
To: linux-m68k@lists.linux-m68k.org
Subject: L68K: Truecolor Linux logo
Sender: owner-linux-m68k@phil.uni-sb.de


Below is a patch that implements drawing the Linux logo for truecolor
visuals. Please note that "truecolor", in X parlance, is different
from "directcolor", which Joe Average User means when he talks about
truecolor. Directcolor is directly mapped, whereas truecolor uses 3
separate palettes for each color space.

The truecolor stuff itself should be straightforward, however, I
couldn't test it... (At least Geert looked at the code :-)

[More text and another patch below!]

------------------------------------------------------------------------------
--- linux-2.1.85/drivers/video/fbcon.c~	Fri Feb 20 10:47:20 1998
+++ linux-2.1.85/drivers/video/fbcon.c	Fri Feb 20 10:46:19 1998
@@ -1107,14 +1107,19 @@
     int i, j, n, x1, y1;
     int logo_depth, done = 0;
 	
-    /* Set colors if visual is PSEUDOCOLOR and we have enough colors */
-    if (p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) {
-	int first_col = depth >= 8 ? 32 : depth > 4 ? 16 : 0;
-	int num_cols = depth >= 8 ? LINUX_LOGO_COLORS : 16;
+    /* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
+     * TRUECOLOR */
+    if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) ||
+	p->visual == FB_VISUAL_TRUECOLOR) {
+	int is_truecolor = (p->visual == FB_VISUAL_TRUECOLOR);
+	int use_256 = (!is_truecolor && depth >= 8) ||
+		      (is_truecolor && depth >= 24);
+	int first_col = use_256 ? 32 : depth > 4 ? 16 : 0;
+	int num_cols = use_256 ? LINUX_LOGO_COLORS : 16;
 	unsigned char *red, *green, *blue;
 	int old_cmap_len;
 	
-	if (depth >= 8) {
+	if (use_256) {
 	    red   = linux_logo_red;
 	    green = linux_logo_green;
 	    blue  = linux_logo_blue;
@@ -1128,7 +1133,7 @@
 	/* dirty trick to avoid setcmap calling kmalloc which isn't
 	 * initialized yet... */
 	old_cmap_len = fb_display[fg_console].cmap.len;
-	fb_display[fg_console].cmap.len = 1 << depth;
+	fb_display[fg_console].cmap.len = 1 << (depth/(is_truecolor ? 3 : 1));
 	
 	for( i = 0; i < num_cols; i += n ) {
 	    n = num_cols - i;
@@ -1147,7 +1152,7 @@
 	}
 	fb_display[fg_console].cmap.len = old_cmap_len;
     }
-
+	
     if (depth >= 8) {
 	logo = linux_logo;
 	logo_depth = 8;
@@ -1163,8 +1168,61 @@
 
 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
     defined(CONFIG_FBCON_CFB32)
-    if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR ||
-			     p->visual == FB_VISUAL_DIRECTCOLOR)) {
+    if (p->visual == FB_VISUAL_TRUECOLOR) {
+	unsigned int val;		/* max. depth 32! */
+	int bdepth;
+	int redshift, greenshift, blueshift;
+		
+	/* Bug: Doesn't obey msb_right ... (who needs that?) */
+	redshift   = p->var.red.offset;
+	greenshift = p->var.green.offset;
+	blueshift  = p->var.blue.offset;
+
+	if (depth >= 24 && (depth % 8) == 0) {
+	    /* have at least 8 bits per color */
+	    src = logo;
+	    bdepth = depth/8;
+	    for( y1 = 0; y1 < LOGO_H; y1++ ) {
+		dst = fb + y1*line;
+		for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
+		    val = (*src << redshift) |
+			  (*src << greenshift) |
+			  (*src << blueshift);
+		    for( i = 0; i < bdepth; ++i )
+			*dst++ = val >> (i*8);
+		}
+	    }
+	}
+	else if (depth >= 15 && depth <= 23) {
+	    /* have 5..7 bits per color, using 16 color image */
+	    unsigned int pix;
+	    src = linux_logo16;
+	    bdepth = (depth+7)/8;
+	    for( y1 = 0; y1 < LOGO_H; y1++ ) {
+		dst = fb + y1*line;
+		for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
+		    pix = (*src >> 4) | 0x10; /* upper nibble */
+		    val = (pix << redshift) |
+			  (pix << greenshift) |
+			  (pix << blueshift);
+		    for( i = 0; i < bdepth; ++i )
+			*dst++ = val >> (i*8);
+		    pix = (*src & 0x0f) | 0x10; /* lower nibble */
+		    val = (pix << redshift) |
+			  (pix << greenshift) |
+			  (pix << blueshift);
+		    for( i = 0; i < bdepth; ++i )
+			*dst++ = val >> (i*8);
+		}
+	    }
+	}
+	
+	done = 1;
+    }
+#endif
+#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
+    defined(CONFIG_FBCON_CFB32)
+    if ((depth % 8 == 0) && (p->visual == FB_VISUAL_DIRECTCOLOR)) {
 	/* Modes without color mapping, needs special data transformation... */
 	unsigned int val;		/* max. depth 32! */
 	int bdepth = depth/8;
------------------------------------------------------------------------------

Now for something different: I think I've once made an error in the
directcolor implementation, which either comes from some
misunderstanding or missing definition:

We have fields {red,green,blue}.offset in struct fb_bitfield, but
nobody ever exactly defined what they mean! So I'd like to define them
now: All offsets are from the right inside a "pixel" value, which is
exactly 'bits_per_pixel' wide (means: you can use the offset as right
argument to <<). A pixel afterwards is a bit stream and is written to
video memory as that unmodified. This implies big-endian byte order if
bits_per_pixel is greater than 8. This definition seems somehow
natural, and should meet current usage.

Graphically explained:

  bits_per_pixel = 16
  red.offset   = 11
  red.length   = 5
  green.offset = 5
  green.length = 6
  blue.offset  = 0
  blue.length  = 5

  15      11 10       5 4      0       bit#
  +---------+----------+--------+
  |   red   |  green   |  blue  |  <-- pixel
  +---------+----------+--------+

  video memory, first 4 pixels:

  0       1       2       3       4       5       6       7          byte#
  +-------+-------+-------+-------+-------+-------+-------+-------+
  |  r |  g  |  b |  r |  g  |  b |  r |  g  |  b |  r |  g  |  b |
  +-------+-------+-------+-------+-------+-------+-------+-------+
  |    Pixel 0    |    Pixel 1    |    Pixel 2    |    Pixel 3    |

  bits_per_pixel = 32
  red.offset   = 16
  red.length   = 8
  green.offset = 8
  green.length = 8
  blue.offset  = 0
  blue.length  = 8

  31    24      16       8        0      bit#
  +-------+-------+-------+-------+
  | empty |  red  | green | blue  |  <-- pixel
  +-------+-------+-------+-------+

  video memory, first 2 pixels:

  0       1       2       3       4       5       6       7          byte#
  +-------+-------+-------+-------+-------+-------+-------+-------+
  | empty |  red  | green |  blue | empty |  red  | green |  blue |
  +-------+-------+-------+-------+-------+-------+-------+-------+
  |             Pixel 0           |             Pixel 1           |


But this definition does not match my interpretation when drawing the
logo... There I do for directcolor (and with the patch above also for
truecolor, to be consistent):

  for( i = 0; i < bdepth; ++i )
    *dst++ = val >> (i*8);

which writes the single bytes in little-endian order! Unfortunately, I
can't remember if I had some thoughts behind this at the time I wrote
it, or if I just was absent-minded...

The patch below fixes this and writes the bytes big-endian. Can
somebody please test this? It should be sufficient to boot a Falcon in
HiColor mode (directcolor, depth 16). There, the logo shouldn't
disappear too fast :-) Can somebody please tell me if colors are
correct with our without this second patch?

Roman

------------------------------------------------------------------------------
--- linux-2.1.85/drivers/video/fbcon.c~	Fri Feb 20 10:46:19 1998
+++ linux-2.1.85/drivers/video/fbcon.c	Fri Feb 20 10:55:14 1998
@@ -1188,7 +1188,7 @@
 		    val = (*src << redshift) |
 			  (*src << greenshift) |
 			  (*src << blueshift);
-		    for( i = 0; i < bdepth; ++i )
+		    for( i = bdepth-1; i >= 0; --i )
 			*dst++ = val >> (i*8);
 		}
 	    }
@@ -1211,7 +1211,7 @@
 		    val = (pix << redshift) |
 			  (pix << greenshift) |
 			  (pix << blueshift);
-		    for( i = 0; i < bdepth; ++i )
+		    for( i = bdepth-1; i >= 0; --i )
 			*dst++ = val >> (i*8);
 		}
 	    }
@@ -1245,7 +1245,7 @@
 		val = ((linux_logo_red[*src]   & redmask)   << redshift) |
 		      ((linux_logo_green[*src] & greenmask) << greenshift) |
 		      ((linux_logo_blue[*src]  & bluemask)  << blueshift);
-		for( i = 0; i < bdepth; ++i )
+		for( i = bdepth-1; i >= 0; --i )
 		    *dst++ = val >> (i*8);
 	    }
 	}
--- linux-2.1.85/include/linux/fb.h~	Tue Jan 13 17:38:11 1998
+++ linux-2.1.85/include/linux/fb.h	Fri Feb 20 11:16:16 1998
@@ -55,6 +55,12 @@
 	__u16 reserved[5];		/* Reserved for future compatibility */
 };
 
+/* Interpretation of offset for color fields: All offsets are from the right,
+ * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you
+ * can use the offset as right argument to <<). A pixel afterwards is a bit
+ * stream and is written to video memory as that unmodified. This implies
+ * big-endian byte order if bits_per_pixel is greater than 8.
+ */
 struct fb_bitfield {
 	__u32 offset;			/* beginning of bitfield	*/
 	__u32 length;			/* length of bitfield		*/
