Index | Thread | Search

From:
Ted Bullock <tbullock@comlore.com>
Subject:
Re: rasops32: fix fonts on byte swapped framebuffers
To:
Crystal Kolipe <kolipe.c@exoticsilicon.com>
Cc:
tech@openbsd.org
Date:
Sun, 11 Oct 2026 16:36:29 -0500

Download raw body.

Thread
Hi Crystal,

Here is the complete patch to the renderer, including your
NRASOPS_BSWAP guard. How do you feel about this version? It works for me
on 32-bit framebuffers.

Ted

--- a/sys/dev/rasops/rasops32.c
+++ b/sys/dev/rasops/rasops32.c
@@ -62,18 +62,15 @@
  * Paint a single character.
  */
 int
 rasops32_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr)
 {
-	int width, height, step, cnt, fs, b, f;
-	uint32_t fb, clr[2];
+	int width, height, step, cnt, fs, first_high;
+	uint32_t fb, clr[2], b, f;
 	struct rasops_info *ri;
-	int64_t *rp;
-	union {
-		int64_t q[4];
-		int32_t d[4][2];
-	} u;
+	uint64_t *rp;
+	uint64_t q[4];
 	u_char *fr;

 	ri = (struct rasops_info *)cookie;

 #ifdef RASOPS_CLIPPING
@@ -83,28 +80,41 @@

 	if ((unsigned)col >= (unsigned)ri->ri_cols)
 		return 0;
 #endif

-	rp = (int64_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
+	rp = (uint64_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);

 	height = ri->ri_font->fontheight;
 	width = ri->ri_font->fontwidth;
 	step = ri->ri_stride >> 3;

 	b = ri->ri_devcmap[(attr >> 16) & 0xf];
 	f = ri->ri_devcmap[(attr >> 24) & 0xf];
-	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;
-	u.d[3][0] = f; u.d[3][1] = f;
+	/* Each table entry contains the colours for two adjacent pixels. */
+	q[0] = (uint64_t)b << 32 | b;
+	q[3] = (uint64_t)f << 32 | f;
+
+	/* A byte swapped framebuffer reverses the two pixels together. */
+	first_high = BYTE_ORDER == BIG_ENDIAN;
+#if NRASOPS_BSWAP > 0
+	if (ri->ri_flg & RI_BSWAP)
+		first_high = !first_high;
+#endif
+	if (first_high) {
+		q[1] = (uint64_t)b << 32 | f;
+		q[2] = (uint64_t)f << 32 | b;
+	} else {
+		q[1] = (uint64_t)f << 32 | b;
+		q[2] = (uint64_t)b << 32 | f;
+	}

 	if (uc == ' ') {
 		while (height--) {
 			/* the general, pixel-at-a-time case is fast enough */
 			for (cnt = 0; cnt < width; cnt++)
-				((int *)rp)[cnt] = b;
+				((uint32_t *)rp)[cnt] = b;
 			rp += step;
 		}
 	} else {
 		uc -= ri->ri_font->firstchar;
 		fr = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
@@ -113,84 +123,84 @@
 		/* double-pixel special cases for the common widths */
 		switch (width) {
 		case 6:
 			while (height--) {
 				fb = fr[0];
-				rp[0] = u.q[fb >> 6];
-				rp[1] = u.q[(fb >> 4) & 3];
-				rp[2] = u.q[(fb >> 2) & 3];
+				rp[0] = q[fb >> 6];
+				rp[1] = q[(fb >> 4) & 3];
+				rp[2] = q[(fb >> 2) & 3];
 				rp += step;
 				fr += 1;
 			}
 			break;

 		case 8:
 			while (height--) {
 				fb = fr[0];
-				rp[0] = u.q[fb >> 6];
-				rp[1] = u.q[(fb >> 4) & 3];
-				rp[2] = u.q[(fb >> 2) & 3];
-				rp[3] = u.q[fb & 3];
+				rp[0] = q[fb >> 6];
+				rp[1] = q[(fb >> 4) & 3];
+				rp[2] = q[(fb >> 2) & 3];
+				rp[3] = q[fb & 3];
 				rp += step;
 				fr += 1;
 			}
 			break;

 		case 12:
 			while (height--) {
 				fb = fr[0];
-				rp[0] = u.q[fb >> 6];
-				rp[1] = u.q[(fb >> 4) & 3];
-				rp[2] = u.q[(fb >> 2) & 3];
-				rp[3] = u.q[fb & 3];
+				rp[0] = q[fb >> 6];
+				rp[1] = q[(fb >> 4) & 3];
+				rp[2] = q[(fb >> 2) & 3];
+				rp[3] = q[fb & 3];
 				fb = fr[1];
-				rp[4] = u.q[fb >> 6];
-				rp[5] = u.q[(fb >> 4) & 3];
+				rp[4] = q[fb >> 6];
+				rp[5] = q[(fb >> 4) & 3];
 				rp += step;
 				fr += 2;
 			}
 			break;

 		case 16:
 			while (height--) {
 				fb = fr[0];
-				rp[0] = u.q[fb >> 6];
-				rp[1] = u.q[(fb >> 4) & 3];
-				rp[2] = u.q[(fb >> 2) & 3];
-				rp[3] = u.q[fb & 3];
+				rp[0] = q[fb >> 6];
+				rp[1] = q[(fb >> 4) & 3];
+				rp[2] = q[(fb >> 2) & 3];
+				rp[3] = q[fb & 3];
 				fb = fr[1];
-				rp[4] = u.q[fb >> 6];
-				rp[5] = u.q[(fb >> 4) & 3];
-				rp[6] = u.q[(fb >> 2) & 3];
-				rp[7] = u.q[fb & 3];
+				rp[4] = q[fb >> 6];
+				rp[5] = q[(fb >> 4) & 3];
+				rp[6] = q[(fb >> 2) & 3];
+				rp[7] = q[fb & 3];
 				rp += step;
 				fr += 2;
 			}
 			break;

 		case 32:
 			while (height--) {
 				fb = fr[0];
-				rp[0] = u.q[fb >> 6];
-				rp[1] = u.q[(fb >> 4) & 3];
-				rp[2] = u.q[(fb >> 2) & 3];
-				rp[3] = u.q[fb & 3];
+				rp[0] = q[fb >> 6];
+				rp[1] = q[(fb >> 4) & 3];
+				rp[2] = q[(fb >> 2) & 3];
+				rp[3] = q[fb & 3];
 				fb = fr[1];
-				rp[4] = u.q[fb >> 6];
-				rp[5] = u.q[(fb >> 4) & 3];
-				rp[6] = u.q[(fb >> 2) & 3];
-				rp[7] = u.q[fb & 3];
+				rp[4] = q[fb >> 6];
+				rp[5] = q[(fb >> 4) & 3];
+				rp[6] = q[(fb >> 2) & 3];
+				rp[7] = q[fb & 3];
 				fb = fr[2];
-				rp[8] = u.q[fb >> 6];
-				rp[9] = u.q[(fb >> 4) & 3];
-				rp[10] = u.q[(fb >> 2) & 3];
-				rp[11] = u.q[fb & 3];
+				rp[8] = q[fb >> 6];
+				rp[9] = q[(fb >> 4) & 3];
+				rp[10] = q[(fb >> 2) & 3];
+				rp[11] = q[fb & 3];
 				fb = fr[3];
-				rp[12] = u.q[fb >> 6];
-				rp[13] = u.q[(fb >> 4) & 3];
-				rp[14] = u.q[(fb >> 2) & 3];
-				rp[15] = u.q[fb & 3];
+				rp[12] = q[fb >> 6];
+				rp[13] = q[(fb >> 4) & 3];
+				rp[14] = q[(fb >> 2) & 3];
+				rp[15] = q[fb & 3];
 				rp += step;
 				fr += 4;
 			}
 			break;

@@ -202,11 +212,11 @@
 				fb = fr[3] | (fr[2] << 8) | (fr[1] << 16) |
 				    (fr[0] << 24);
 				fr += fs;

 				for (cnt = 0; cnt < width; cnt++) {
-					((int *)rp)[cnt] = clr[fb >> 31];
+					((uint32_t *)rp)[cnt] = clr[fb >> 31];
 					fb <<= 1;
 				}
 				rp += step;
 			}
 			break;
@@ -215,10 +225,10 @@

 	/* Do underline a pixel at a time */
 	if ((attr & WSATTR_UNDERLINE) != 0) {
 		rp -= step;
 		for (cnt = 0; cnt < width; cnt++)
-			((int *)rp)[cnt] = f;
+			((uint32_t *)rp)[cnt] = f;
 	}

 	return 0;
 }


On Sun, 11 Oct 2026 14:49:26 -0500, Ted Bullock <tbullock@comlore.com> wrote:
> Agreed, I had missed that.
>
> Ted
>
>
> On Sat, 10 Oct 2026 09:48:04 -0000, Crystal Kolipe <kolipe.c@exoticsilicon.com> wrote:
> > On Fri, Oct 09, 2026 at 09:41:37AM -0600, Ted Bullock wrote:
> > > Here is your version with unsigned colours and the pixel pair order adjusted
> > > for both CPU byte order and RI_BSWAP. The existing drawing loops are unchanged.
> >
> > This looks correct, but we are missing a preprocessor #if :
> >
> > > +	/* A byte swapped framebuffer reverses the two pixels together. */
> > > +	first_high = BYTE_ORDER == BIG_ENDIAN;
> >
> > #if NRASOPS_BSWAP > 0
> >
> > > +	if (ri->ri_flg & RI_BSWAP)
> > > +		first_high = !first_high;
> >
> > #endif