Here is a set of diffs that implement 256 colour support on wscons for 32-bit
rasops displays.

With this applied, the following control sequences are recognised:

CSI 38;5;Xm - set foreground colour X from a palette of 256.
CSI 48;5;Xm - set background colour X from a palette of 256.

Also implemented are CSI 90-97 and CSI 100-107 to set the bright versions of
the regular eight colours directly, (as made popular by aixterm).

Support for anti-aliased fonts is included, and the additional colours are
anti-aliased in the same way as regular colours.

The diffs apply to NetBSD 10.1-release.  This version of the code has been
lightly tested and seems to work as expected.

I developed this, (and various other console enhancements), as part of a
larger patchset for OpenBSD which has been in use locally here at
Exotic Silicon since 2022.  I separated out the 256 colour code and ported it
to NetBSD first, but the other features would probably be fairly easy to port
as well if there is any interest.

diff -ur sys.dist/dev/rasops/rasops.c sys/dev/rasops/rasops.c
--- sys.dist/dev/rasops/rasops.c        2022-05-15 16:43:39.000000000 +0000
+++ sys/dev/rasops/rasops.c     2025-07-06 17:43:29.800716828 +0000
@@ -80,6 +80,8 @@
        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 @@
 };
 
 /* 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
@@ -551,6 +583,7 @@
 #endif
 #if NRASOPS32 > 0
        case 32:
+               ri->ri_caps |= WSSCREEN_256COL;
                rasops32_init(ri);
                break;
 #endif
@@ -619,8 +652,8 @@
                return EINVAL;
 
 #ifdef RASOPS_CLIPPING
-       fg &= 7;
-       bg &= 7;
+       fg &= 0xff;
+       bg &= 0xff;
 #endif
 
        if ((flg & WSATTR_BLINK) != 0)
@@ -904,7 +937,7 @@
 
        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
@@ -959,6 +992,31 @@
                        c |= (c & 0xff) << 24;
                        break;
                case 32:
+#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];
+                       }
                        if ((ri->ri_flg & RI_BSWAP) != 0)
                                c = bswap32(c);
                        break;
@@ -975,8 +1033,8 @@
 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;
 }
diff -ur sys.dist/dev/rasops/rasops.h sys/dev/rasops/rasops.h
--- sys.dist/dev/rasops/rasops.h        2021-12-24 18:12:58.000000000 +0000
+++ sys/dev/rasops/rasops.h     2025-07-06 16:45:39.917990816 +0000
@@ -144,7 +144,7 @@
        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;
@@ -189,6 +189,7 @@
 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
 /*
@@ -202,11 +203,11 @@
 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)))
 
diff -ur sys.dist/dev/rasops/rasops_putchar.h sys/dev/rasops/rasops_putchar.h
--- sys.dist/dev/rasops/rasops_putchar.h        2019-08-10 01:24:17.000000000 
+0000
+++ sys/dev/rasops/rasops_putchar.h     2025-07-06 17:35:31.889974663 +0000
@@ -151,15 +151,24 @@
                /*
                 * 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--) {
diff -ur sys.dist/dev/wscons/wsdisplayvar.h sys/dev/wscons/wsdisplayvar.h
--- sys.dist/dev/wscons/wsdisplayvar.h  2023-03-20 17:24:15.000000000 +0000
+++ sys/dev/wscons/wsdisplayvar.h       2025-07-05 19:11:58.649312512 +0000
@@ -107,6 +107,7 @@
 #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;
 };
 
diff -ur sys.dist/dev/wscons/wsemul_vt100_subr.c 
sys/dev/wscons/wsemul_vt100_subr.c
--- sys.dist/dev/wscons/wsemul_vt100_subr.c     2023-07-30 11:47:08.000000000 
+0000
+++ sys/dev/wscons/wsemul_vt100_subr.c  2025-07-06 13:13:45.724547638 +0000
@@ -546,6 +546,26 @@
                                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;
@@ -555,9 +575,37 @@
                                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:
+                               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:
+                               flags |= WSATTR_WSCOLORS;
+                               bgcol = ARG(vd, n) - 92;
+                               break;
                            default:
 #ifdef VT100_PRINTUNKNOWN
                                printf("CSI%dm unknown\n", ARG(vd, n));

Reply via email to