tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Support 256 colours on wscons
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));
Home |
Main Index |
Thread Index |
Old Index