tech-kern archive

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

Re: Support 256 colours on wscons



Hi! Thanks for working on this.

While testing this patch (with a little script that outputs all the
xterm 256 color escapes), I noticed that it only works for 32-bit
wsdisplays.

You can try out a range of colour depths using the "vesa" option
in the bios bootloader, for example, in qemu-system-i386.

I've made a few adjustments to dev/rasops so that 8/16/24-bit
wsdisplays can also use the 256-color extensions. It seems to work.

I'm not sure the reproduction on 8-bit displays is 100% perfect
(certainly the antialiasing could be prettier when using an
antialiased font), but it's definitely usable.

Updated patch and the test script are attached.

Attachment: simple-256.sh
Description: Bourne shell script

Index: dev/wscons/wsemul_vt100_subr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wsemul_vt100_subr.c,v
retrieving revision 1.34
diff -u -p -r1.34 wsemul_vt100_subr.c
--- dev/wscons/wsemul_vt100_subr.c	3 Aug 2023 22:11:41 -0000	1.34
+++ dev/wscons/wsemul_vt100_subr.c	28 Oct 2025 12:35:24 -0000
@@ -561,6 +561,26 @@ wsemul_vt100_handle_csi(struct vt100base
 				flags |= WSATTR_WSCOLORS;
 				fgcol = ARG(vd, n) - 30;
 				break;
+#define EXIST_ARG2(i) ((vd->nargs - i) >= 3)
+#define ARG2_OR_DEF(i) (EXIST_ARG2(i) ? ARG(vd, i + 2) : 0)
+			    case 38:
+				if (vd->nargs == n + 1)
+					break;
+				if (ARG(vd, n + 1) == 5) {
+					flags |= WSATTR_WSCOLORS;
+					if (vd->scrcapabilities &
+					    WSSCREEN_256COL)
+						fgcol = ARG2_OR_DEF(n);
+					n += (EXIST_ARG2(n) ? 2 : 1);
+					break;
+				}
+				if (ARG(vd, n + 1) == 2) {
+					n = (vd->nargs - n > 5 ? n + 4 :
+					    vd->nargs);
+					break;
+				}
+				n++;
+				break;
 			    case 39:
 				fgcol = vd->msgattrs.default_fg;
 				break;
@@ -570,9 +590,39 @@ wsemul_vt100_handle_csi(struct vt100base
 				flags |= WSATTR_WSCOLORS;
 				bgcol = ARG(vd, n) - 40;
 				break;
+			    case 48:
+				if (vd->nargs == n + 1)
+					break;
+				if (ARG(vd, n + 1) == 5) {
+					flags |= WSATTR_WSCOLORS;
+					if (vd->scrcapabilities &
+					    WSSCREEN_256COL)
+						bgcol = ARG2_OR_DEF(n);
+					n += (EXIST_ARG2(n) ? 2 : 1);
+					break;
+				}
+				if (ARG(vd, n + 1) == 2) {
+					n = (vd->nargs - n > 5 ? n + 4 :
+					    vd->nargs);
+					break;
+				}
+				n++;
+				break;
 			    case 49:
 				bgcol = vd->msgattrs.default_bg;
 				break;
+			    case 90: case 91: case 92: case 93:
+			    case 94: case 95: case 96: case 97:
+				/* bright foreground color */
+				flags |= WSATTR_WSCOLORS;
+				fgcol = ARG(vd, n) - 82;
+				break;
+			    case 100: case 101: case 102: case 103:
+			    case 104: case 105: case 106: case 107:
+				/* bright background color */
+				flags |= WSATTR_WSCOLORS;
+				bgcol = ARG(vd, n) - 92;
+				break;
 			    default:
 #ifdef VT100_PRINTUNKNOWN
 				printf("CSI%dm unknown\n", ARG(vd, n));
Index: dev/wscons/wsdisplayvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wsdisplayvar.h,v
retrieving revision 1.57
diff -u -p -r1.57 wsdisplayvar.h
--- dev/wscons/wsdisplayvar.h	1 Mar 2023 08:42:33 -0000	1.57
+++ dev/wscons/wsdisplayvar.h	28 Oct 2025 12:35:24 -0000
@@ -107,6 +107,7 @@ struct wsscreen_descr {
 #define WSSCREEN_RESIZE		32	/* can resize */
 #define WSSCREEN_FREE		64	/* free() this struct when deleting
 					 * internal only, do not set */
+#define WSSCREEN_256COL		128
 	void *modecookie;
 };
 
Index: dev/rasops/rasops.c
===================================================================
RCS file: /cvsroot/src/sys/dev/rasops/rasops.c,v
retrieving revision 1.128
diff -u -p -r1.128 rasops.c
--- dev/rasops/rasops.c	15 May 2022 16:43:39 -0000	1.128
+++ dev/rasops/rasops.c	28 Oct 2025 12:35:24 -0000
@@ -80,6 +80,8 @@ static const uint32_t rasops_rmask32[4 +
 	MBE(0xffffffff),
 };
 
+uint8_t rasops_ecmap[256 * 3];
+
 /* ANSI colormap (R,G,B). Upper 8 are high-intensity */
 const uint8_t rasops_cmap[256 * 3] = {
 	0x00, 0x00, 0x00, /* black */
@@ -140,9 +142,39 @@ const uint8_t rasops_cmap[256 * 3] = {
 };
 
 /* True if color is gray */
-static const uint8_t rasops_isgray[16] = {
+static const uint8_t rasops_isgray[256] = {
 	1, 0, 0, 0, 0, 0, 0, 1,
 	1, 0, 0, 0, 0, 0, 0, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
 };
 
 #ifdef RASOPS_APPLE_PALETTE
@@ -535,22 +567,26 @@ rasops_reconfig(struct rasops_info *ri, 
 #endif
 #if NRASOPS8 > 0
 	case 8:
+		ri->ri_caps |= WSSCREEN_256COL;
 		rasops8_init(ri);
 		break;
 #endif
 #if (NRASOPS15 + NRASOPS16) > 0
 	case 15:
 	case 16:
+		ri->ri_caps |= WSSCREEN_256COL;
 		rasops15_init(ri);
 		break;
 #endif
 #if NRASOPS24 > 0
 	case 24:
+		ri->ri_caps |= WSSCREEN_256COL;
 		rasops24_init(ri);
 		break;
 #endif
 #if NRASOPS32 > 0
 	case 32:
+		ri->ri_caps |= WSSCREEN_256COL;
 		rasops32_init(ri);
 		break;
 #endif
@@ -619,8 +655,8 @@ rasops_allocattr_color(void *cookie, int
 		return EINVAL;
 
 #ifdef RASOPS_CLIPPING
-	fg &= 7;
-	bg &= 7;
+	fg &= 0xff;
+	bg &= 0xff;
 #endif
 
 	if ((flg & WSATTR_BLINK) != 0)
@@ -904,7 +940,7 @@ rasops_init_devcmap(struct rasops_info *
 
 	p = rasops_cmap;
 
-	for (i = 0; i < 16; i++) {
+	for (i = 0; i < ((ri->ri_caps & WSSCREEN_256COL) ? 256 : 16); i++) {
 		if (ri->ri_rnum <= 8)
 			c = (uint32_t)(*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
 		else
@@ -923,6 +959,32 @@ rasops_init_devcmap(struct rasops_info *
 			c |= (uint32_t)(*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
 		p++;
 
+#define EP_BLUE_RAW(x) (48 * ((x - 16) % 6))
+#define EP_GREEN_RAW(x) (48 * (((x - 16)/6) % 6))
+#define EP_RED_RAW(x) (48 * (((x - 16)/36) % 6))
+#define EP_BLUE(x) ((EP_BLUE_RAW(x) >> (8 - ri->ri_bnum)) << ri->ri_bpos)
+#define EP_GREEN(x) ((EP_GREEN_RAW(x) >> (8 - ri->ri_gnum)) << ri->ri_gpos)
+#define EP_RED(x) ((EP_RED_RAW(x) >> (8 - ri->ri_rnum)) << ri->ri_rpos)
+#define EP_COL(x) EP_RED(x) | EP_GREEN(x) | EP_BLUE(x)
+#define EP_GREY_BYTE(x) (1 + ((x - 232) * 11))
+#define GREYSCALE_BLUE(x) ((EP_GREY_BYTE(x) >> (8 - ri->ri_bnum)) << ri->ri_bpos)
+#define GREYSCALE_GREEN(x) ((EP_GREY_BYTE(x) >> (8 - ri->ri_gnum)) << ri->ri_gpos)
+#define GREYSCALE_RED(x) ((EP_GREY_BYTE(x) >> (8 - ri->ri_rnum)) << ri->ri_rpos)
+#define EP_GREY(x) GREYSCALE_RED(x) | GREYSCALE_GREEN(x) | GREYSCALE_BLUE(x)
+		if (i >= 16) {
+			rasops_ecmap[i * 3] =
+			    (i < 232 ? EP_RED_RAW(i) : EP_GREY_BYTE(i));
+			rasops_ecmap[i * 3 + 1] =
+			    (i < 232 ? EP_GREEN_RAW(i) : EP_GREY_BYTE(i));
+			rasops_ecmap[i * 3 + 2] =
+			    (i < 232 ? EP_BLUE_RAW(i) : EP_GREY_BYTE(i));
+			c = (i < 232 ? EP_COL(i) : EP_GREY(i));
+		} else {
+			rasops_ecmap[i * 3] = rasops_cmap[i * 3];
+			rasops_ecmap[i * 3 + 1] = rasops_cmap[i * 3 + 1];
+			rasops_ecmap[i * 3 + 2] = rasops_cmap[i * 3 + 2];
+		}
+
 		/*
 		 * Swap byte order if necessary. Then, fill the word for
 		 * generic routines, which want this.
@@ -975,8 +1037,8 @@ void
 rasops_unpack_attr(long attr, int *fg, int *bg, int *underline)
 {
 
-	*fg = ((uint32_t)attr >> 24) & 0xf;
-	*bg = ((uint32_t)attr >> 16) & 0xf;
+	*fg = ((uint32_t)attr >> 24) & 0xff;
+	*bg = ((uint32_t)attr >> 16) & 0xff;
 	if (underline != NULL)
 		*underline = (uint32_t)attr & WSATTR_UNDERLINE;
 }
Index: dev/rasops/rasops.h
===================================================================
RCS file: /cvsroot/src/sys/dev/rasops/rasops.h,v
retrieving revision 1.51
diff -u -p -r1.51 rasops.h
--- dev/rasops/rasops.h	25 Jul 2025 18:19:12 -0000	1.51
+++ dev/rasops/rasops.h	28 Oct 2025 12:35:24 -0000
@@ -145,7 +145,7 @@ struct rasops_info {
 	int	ri_xorigin;	/* where ri_bits begins (x) */
 	int	ri_yorigin;	/* where ri_bits begins (y) */
 	uint32_t
-		ri_devcmap[16]; /* color -> framebuffer data */
+		ri_devcmap[256]; /* color -> framebuffer data */
 
 	/* The emulops you need to use, and the screen caps for wscons */
 	struct	wsdisplay_emulops ri_ops;
@@ -190,6 +190,7 @@ void	rasops_erasecols(void *, int, int, 
 int	rasops_get_cmap(struct rasops_info *, uint8_t *, size_t);
 
 extern const uint8_t	rasops_cmap[256 * 3];
+extern uint8_t	rasops_ecmap[256 * 3];
 
 #ifdef _RASOPS_PRIVATE
 /*
@@ -203,11 +204,11 @@ void	rasops15_init(struct rasops_info *)
 void	rasops24_init(struct rasops_info *);
 void	rasops32_init(struct rasops_info *);
 
-#define	ATTR_BG(ri, attr) ((ri)->ri_devcmap[((uint32_t)(attr) >> 16) & 0xf])
-#define	ATTR_FG(ri, attr) ((ri)->ri_devcmap[((uint32_t)(attr) >> 24) & 0xf])
+#define	ATTR_BG(ri, attr) ((ri)->ri_devcmap[((uint32_t)(attr) >> 16) & 0xff])
+#define	ATTR_FG(ri, attr) ((ri)->ri_devcmap[((uint32_t)(attr) >> 24) & 0xff])
 
-#define	ATTR_MASK_BG __BITS(16, 19)
-#define	ATTR_MASK_FG __BITS(24, 27)
+#define	ATTR_MASK_BG __BITS(16, 23)
+#define	ATTR_MASK_FG __BITS(24, 31)
 
 #define	DELTA(p, d, cast) ((p) = (cast)((uint8_t *)(p) + (d)))
 
Index: dev/rasops/rasops_putchar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/rasops/rasops_putchar.h,v
retrieving revision 1.8
diff -u -p -r1.8 rasops_putchar.h
--- dev/rasops/rasops_putchar.h	10 Aug 2019 01:24:17 -0000	1.8
+++ dev/rasops/rasops_putchar.h	28 Oct 2025 12:35:24 -0000
@@ -151,15 +151,24 @@ NAME(RASOPS_DEPTH)(void *cookie, int row
 		/*
 	 	 * This is independent to positions/lengths of RGB in pixel.
 	 	 */
-		off[0] = (((uint32_t)attr >> 16) & 0xf) * 3;
-		off[1] = (((uint32_t)attr >> 24) & 0xf) * 3;
+		off[0] = (((uint32_t)attr >> 16) & 0xff) * 3;
+		off[1] = (((uint32_t)attr >> 24) & 0xff) * 3;
 
-		r[0] = rasops_cmap[off[0]];
-		r[1] = rasops_cmap[off[1]];
-		g[0] = rasops_cmap[off[0] + 1];
-		g[1] = rasops_cmap[off[1] + 1];
-		b[0] = rasops_cmap[off[0] + 2];
-		b[1] = rasops_cmap[off[1] + 2];
+		if (ri->ri_caps & WSSCREEN_256COL) {
+			r[0] = rasops_ecmap[off[0]];
+			r[1] = rasops_ecmap[off[1]];
+			g[0] = rasops_ecmap[off[0] + 1];
+			g[1] = rasops_ecmap[off[1] + 1];
+			b[0] = rasops_ecmap[off[0] + 2];
+			b[1] = rasops_ecmap[off[1] + 2];
+		} else {
+			r[0] = rasops_cmap[off[0]];
+			r[1] = rasops_cmap[off[1]];
+			g[0] = rasops_cmap[off[0] + 1];
+			g[1] = rasops_cmap[off[1] + 1];
+			b[0] = rasops_cmap[off[0] + 2];
+			b[1] = rasops_cmap[off[1] + 2];
+		}
 #endif
 
 		while (height--) {


Home | Main Index | Thread Index | Old Index