Download raw body.
wscons 256 colour support
This patch adds support for 256 colours to wscons on 32-bit displays.
I originally posted a version of this back in 2023, as part of a larger
console enhancement diff, but the 256 colour part is usable completely
independently of the other enhancements.
Since we now have enough support already in for the other control sequences
necessary for TERM=xterm-256color to display output on wscons, it seems like a
good time to revisit this 256 colour code.
It's been in use here for over two years without problems.
--- sys/dev/rasops/rasops.c Thu Jun 12 19:39:02 2025
+++ sys/dev/rasops/rasops.c Thu Jun 12 19:41:57 2025
@@ -446,6 +446,10 @@
WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
}
+ if (ri->ri_depth == 32) {
+ ri->ri_caps |= WSSCREEN_256COL;
+ }
+
switch (ri->ri_depth) {
#if NRASOPS1 > 0
case 1:
@@ -557,7 +561,7 @@
if ((flg & WSATTR_HILIT) != 0 && fg < 8)
fg += 8;
- *attr = (bg << 16) | (fg << 24) | (flg & WSATTR_UNDERLINE);
+ *attr = (bg << 16) | (fg << 24) | flg;
return (0);
}
@@ -581,7 +585,7 @@
bg = swap;
}
- *attr = (bg << 16) | (fg << 24) | (flg & WSATTR_UNDERLINE);
+ *attr = (bg << 16) | (fg << 24) | flg;
return (0);
}
@@ -863,6 +867,24 @@
ri->ri_devcmap[i] = c;
#endif
}
+ /* Define colours 16-255 if we are running in 32bpp or 16bpp */
+ #define EBCOL_BLUE(x) ((48*((x-16)%6) >> (8 - ri->ri_bnum)) << ri->ri_bpos)
+ #define EBCOL_GREEN(x) (((48*(((x-16)/6)%6)) >> (8 - ri->ri_gnum)) << ri->ri_gpos)
+ #define EBCOL_RED(x) (((48*(((x-16)/36)%6)) >> (8 - ri->ri_rnum)) << ri->ri_rpos)
+ #define EBCOL(x) EBCOL_RED(x) | EBCOL_GREEN(x) | EBCOL_BLUE(x)
+ #define EBGREY_CHANNEL(x) (int)(1+((i-232)*11))
+ #define EBGREY_R(x)(( EBGREY_CHANNEL(x) >> (8 - ri->ri_rnum)) << ri->ri_rpos)
+ #define EBGREY_G(x)(( EBGREY_CHANNEL(x) >> (8 - ri->ri_gnum)) << ri->ri_gpos)
+ #define EBGREY_B(x)(( EBGREY_CHANNEL(x) >> (8 - ri->ri_bnum)) << ri->ri_bpos)
+ #define EBGREY(x) EBGREY_R(x) | EBGREY_G(x) | EBGREY_B(x)
+ if (ri->ri_depth == 32) {
+ for (i=16 ; i<256; i++) {
+ c = (i < 232 ? EBCOL(i) : EBGREY(i));
+ if (ri->ri_flg & RI_BSWAP)
+ c = swap32(c);
+ ri->ri_devcmap[i] = c;
+ }
+ }
#endif
}
@@ -872,8 +894,8 @@
void
rasops_unpack_attr(void *cookie, uint32_t attr, int *fg, int *bg, int *underline)
{
- *fg = ((u_int)attr >> 24) & 0xf;
- *bg = ((u_int)attr >> 16) & 0xf;
+ *fg = ((u_int)attr >> 24) & 0xff;
+ *bg = ((u_int)attr >> 16) & 0xff;
if (underline != NULL)
*underline = (u_int)attr & WSATTR_UNDERLINE;
}
@@ -903,7 +925,7 @@
return 0;
#endif
- clr = ri->ri_devcmap[(attr >> 16) & 0xf];
+ clr = ri->ri_devcmap[(attr >> 16) & 0xff];
/*
* XXX The wsdisplay_emulops interface seems a little deficient in
@@ -1257,7 +1279,7 @@
/* XXX this assumes 16-bit color depth */
if ((attr & WSATTR_UNDERLINE) != 0) {
- int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf];
+ int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xff];
while (height--) {
*(int16_t *)rp = c;
@@ -1788,8 +1810,8 @@
attr = ri->ri_bs[off].attr;
if ((ri->ri_flg & RI_CURSOR) == 0) {
- fg = ((u_int)attr >> 24) & 0xf;
- bg = ((u_int)attr >> 16) & 0xf;
+ fg = ((u_int)attr >> 24) & 0xff;
+ bg = ((u_int)attr >> 16) & 0xff;
attr &= ~0x0ffff0000;
attr |= (fg << 16) | (bg << 24);
}
--- sys/dev/rasops/rasops.h Mon Apr 7 04:25:22 2025
+++ sys/dev/rasops/rasops.h Thu Jun 12 19:41:57 2025
@@ -106,7 +106,7 @@
u_char *ri_origbits; /* where screen bits actually start */
int ri_xorigin; /* where ri_bits begins (x) */
int ri_yorigin; /* where ri_bits begins (y) */
- int32_t ri_devcmap[16]; /* color -> framebuffer data */
+ int32_t ri_devcmap[256]; /* color -> framebuffer data */
/* The emulops you need to use, and the screen caps for wscons */
struct wsdisplay_emulops ri_ops;
--- sys/dev/rasops/rasops32.c Mon Apr 7 04:25:22 2025
+++ sys/dev/rasops/rasops32.c Thu Jun 12 19:41:57 2025
@@ -91,8 +91,8 @@
width = ri->ri_font->fontwidth;
step = ri->ri_stride >> 3;
- b = ri->ri_devcmap[(attr >> 16) & 0xf];
- f = ri->ri_devcmap[(attr >> 24) & 0xf];
+ b = ri->ri_devcmap[(attr >> 16) & 0xff];
+ f = ri->ri_devcmap[(attr >> 24) & 0xff];
u.d[0][0] = b; u.d[0][1] = b;
u.d[1][0] = b; u.d[1][1] = f;
u.d[2][0] = f; u.d[2][1] = b;
--- sys/dev/wscons/wsdisplayvar.h Mon Apr 7 04:25:23 2025
+++ sys/dev/wscons/wsdisplayvar.h Thu Jun 12 19:41:57 2025
@@ -114,6 +114,7 @@
#define WSSCREEN_HILIT 4 /* can highlight (however) */
#define WSSCREEN_BLINK 8 /* can blink */
#define WSSCREEN_UNDERLINE 16 /* can underline */
+#define WSSCREEN_256COL 32 /* supports 256 colours */
};
/*
--- sys/dev/wscons/wsemul_vt100_subr.c Mon Apr 7 04:42:48 2025
+++ sys/dev/wscons/wsemul_vt100_subr.c Thu Jun 12 19:41:57 2025
@@ -630,6 +630,64 @@
flags |= WSATTR_WSCOLORS;
fgcol = ARG(n) - 30;
break;
+ /*
+ * Sequences starting CSI 38 escape to a larger
+ * colourspace, typically either 256 colours or 24-bit.
+ *
+ * We support CSI 38;5;X;m to set colour X from a
+ * palette of 256.
+ */
+#define EXIST_ARG2(i) ((edp->nargs-n)>=3)
+#define ARG2_OR_DEF(i) (EXIST_ARG2(i) ? ARG(i+2) : 0)
+ case 38:
+ /*
+ * 38 followed by zero arguments is meaningless.
+ */
+ if (edp->nargs == n+1) {
+ break ;
+ }
+ /*
+ * 5 should normally be followed by a single
+ * argument, but zero arguments is also valid to
+ * set colour zero.
+ */
+ if (ARG(n+1)==5) {
+ flags |= WSATTR_WSCOLORS;
+ if (edp->scrcapabilities &
+ WSSCREEN_256COL) {
+ fgcol = ARG2_OR_DEF(n);
+ } else {
+ fgcol = (ARG2_OR_DEF(n) < 8 ?
+ ARG2_OR_DEF(n) : fgcol );
+ }
+ n+=(EXIST_ARG2(n) ? 2 : 1);
+ break;
+ }
+ /*
+ * 2 should introduce a sequence of three
+ * arguments, specifying RGB.
+ *
+ * We don't, (yet!), support setting colours by
+ * 24-bit RGB arguments and don't want to
+ * interpret these as regular SGR codes.
+ *
+ * If there are more then three, skip just
+ * three, otherwise skip all of them.
+ */
+ if (ARG(n+1)==2) {
+ n=(edp->nargs-n > 5 ? n+4 :
+ edp->nargs);
+ break;
+ }
+ /*
+ * Invalid code, I.E. not 2 or 5.
+ *
+ * We do what xterm does and just skip the
+ * single unrecognised argument, then allow any
+ * following arguments to be interpreted as SGR.
+ */
+ n++;
+ break;
case 39:
/* reset fg color */
fgcol = WSCOL_WHITE;
@@ -642,6 +700,29 @@
flags |= WSATTR_WSCOLORS;
bgcol = ARG(n) - 40;
break;
+ case 48: /* set 8-bit background colour */
+ if (edp->nargs == n+1) {
+ break ;
+ }
+ if (ARG(n+1)==5) {
+ flags |= WSATTR_WSCOLORS;
+ if (edp->scrcapabilities &
+ WSSCREEN_256COL) {
+ bgcol = ARG2_OR_DEF(n);
+ } else {
+ bgcol = (ARG2_OR_DEF(n) < 8 ?
+ ARG2_OR_DEF(n) : bgcol );
+ }
+ n+=(EXIST_ARG2(n) ? 2 : 1);
+ break;
+ }
+ if (ARG(n+1)==2) {
+ n=(edp->nargs-n > 5 ? n+4 :
+ edp->nargs);
+ break;
+ }
+ n++;
+ break;
case 49:
/* reset bg color */
bgcol = WSCOL_BLACK;
wscons 256 colour support