rasops24.c revision 1.41
1/* 	$NetBSD: rasops24.c,v 1.41 2019/07/31 02:04:14 rin Exp $	*/
2
3/*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: rasops24.c,v 1.41 2019/07/31 02:04:14 rin Exp $");
34
35#include "opt_rasops.h"
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/time.h>
40
41#include <machine/endian.h>
42#include <sys/bswap.h>
43
44#include <dev/wscons/wsdisplayvar.h>
45#include <dev/wscons/wsconsio.h>
46
47#define	_RASOPS_PRIVATE
48#include <dev/rasops/rasops.h>
49
50static void 	rasops24_erasecols(void *, int, int, int, long);
51static void 	rasops24_eraserows(void *, int, int, long);
52static void 	rasops24_putchar(void *, int, int, u_int, long);
53static void 	rasops24_putchar_aa(void *, int, int, u_int, long);
54#ifndef RASOPS_SMALL
55static void 	rasops24_putchar8(void *, int, int, u_int, long);
56static void 	rasops24_putchar12(void *, int, int, u_int, long);
57static void 	rasops24_putchar16(void *, int, int, u_int, long);
58static void	rasops24_makestamp(struct rasops_info *, long);
59#endif
60
61/*
62 * offset = STAMP_SHIFT(fontbits, nibble #) & STAMP_MASK
63 * destination uint32_t[0] = STAMP_READ(offset)
64 * destination uint32_t[1] = STAMP_READ(offset + 4)
65 * destination uint32_t[2] = STAMP_READ(offset + 8)
66 */
67#define	STAMP_SHIFT(fb, n)	((n) ? (fb) : (fb) << 4)
68#define	STAMP_MASK		(0xf << 4)
69#define	STAMP_READ(o)		(*(uint32_t *)((uint8_t *)stamp + (o)))
70
71/*
72 * Initialize rasops_info struct for this colordepth.
73 */
74void
75rasops24_init(struct rasops_info *ri)
76{
77
78	if (ri->ri_rnum == 0) {
79		ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
80
81		ri->ri_rpos = 0;
82		ri->ri_gpos = 8;
83		ri->ri_bpos = 16;
84	}
85
86	ri->ri_ops.erasecols = rasops24_erasecols;
87	ri->ri_ops.eraserows = rasops24_eraserows;
88
89	if (FONT_IS_ALPHA(ri->ri_font)) {
90		ri->ri_ops.putchar = rasops24_putchar_aa;
91		return;
92	}
93
94	switch (ri->ri_font->fontwidth) {
95#ifndef RASOPS_SMALL
96	case 8:
97		ri->ri_ops.putchar = rasops24_putchar8;
98		break;
99	case 12:
100		ri->ri_ops.putchar = rasops24_putchar12;
101		break;
102	case 16:
103		ri->ri_ops.putchar = rasops24_putchar16;
104		break;
105#endif
106	default:
107		ri->ri_ops.putchar = rasops24_putchar;
108		return;
109	}
110
111#ifndef RASOPS_SMALL
112	rasops_allocstamp(ri, sizeof(uint32_t) * 64);
113#endif
114}
115
116#define	RASOPS_DEPTH	24
117#include "rasops_putchar.h"
118#include "rasops_putchar_aa.h"
119
120#ifndef RASOPS_SMALL
121/*
122 * Recompute the blitting stamp.
123 */
124static void
125rasops24_makestamp(struct rasops_info *ri, long attr)
126{
127	uint32_t *stamp = (uint32_t *)ri->ri_stamp;
128	uint32_t fg, bg, c1, c2, c3, c4;
129	int i;
130
131	fg = ri->ri_devcmap[((uint32_t)attr >> 24) & 0xf] & 0xffffff;
132	bg = ri->ri_devcmap[((uint32_t)attr >> 16) & 0xf] & 0xffffff;
133	ri->ri_stamp_attr = attr;
134
135	for (i = 0; i < 64; i += 4) {
136#if BYTE_ORDER == LITTLE_ENDIAN
137		c1 = i & 32 ? fg : bg;
138		c2 = i & 16 ? fg : bg;
139		c3 = i &  8 ? fg : bg;
140		c4 = i &  4 ? fg : bg;
141#else
142		c1 = i &  8 ? fg : bg;
143		c2 = i &  4 ? fg : bg;
144		c3 = i & 16 ? fg : bg;
145		c4 = i & 32 ? fg : bg;
146#endif
147		stamp[i + 0] = (c1 <<  8) | (c2 >> 16);
148		stamp[i + 1] = (c2 << 16) | (c3 >>  8);
149		stamp[i + 2] = (c3 << 24) |  c4;
150
151#if BYTE_ORDER == LITTLE_ENDIAN
152		if ((ri->ri_flg & RI_BSWAP) == 0) {
153#else
154		if ((ri->ri_flg & RI_BSWAP) != 0) {
155#endif
156			stamp[i + 0] = bswap32(stamp[i + 0]);
157			stamp[i + 1] = bswap32(stamp[i + 1]);
158			stamp[i + 2] = bswap32(stamp[i + 2]);
159		}
160	}
161}
162
163#define	RASOPS_WIDTH	8
164#include "rasops_putchar_width.h"
165#undef	RASOPS_WIDTH
166
167#define	RASOPS_WIDTH	12
168#include "rasops_putchar_width.h"
169#undef	RASOPS_WIDTH
170
171#define	RASOPS_WIDTH	16
172#include "rasops_putchar_width.h"
173#undef	RASOPS_WIDTH
174
175#endif	/* !RASOPS_SMALL */
176
177/*
178 * Erase rows. This is nice and easy due to alignment.
179 */
180static void
181rasops24_eraserows(void *cookie, int row, int num, long attr)
182{
183	struct rasops_info *ri = (struct rasops_info *)cookie;
184	int n9, n3, n1, cnt, stride;
185	uint32_t *rp, *dp, *hp, clr, stamp[3];
186
187	hp = NULL;	/* XXX GCC */
188
189	/*
190	 * If the color is gray, we can cheat and use the generic routines
191	 * (which are faster, hopefully) since the r,g,b values are the same.
192	 */
193	if ((attr & WSATTR_PRIVATE2) != 0) {
194		rasops_eraserows(cookie, row, num, attr);
195		return;
196	}
197
198#ifdef RASOPS_CLIPPING
199	if (row < 0) {
200		num += row;
201		row = 0;
202	}
203
204	if (row + num > ri->ri_rows)
205		num = ri->ri_rows - row;
206
207	if (num <= 0)
208		return;
209#endif
210
211	clr = ri->ri_devcmap[((uint32_t)attr >> 16) & 0xf] & 0xffffff;
212	stamp[0] = (clr <<  8) | (clr >> 16);
213	stamp[1] = (clr << 16) | (clr >>  8);
214	stamp[2] = (clr << 24) |  clr;
215
216#if BYTE_ORDER == LITTLE_ENDIAN
217	if ((ri->ri_flg & RI_BSWAP) == 0) {
218#else
219	if ((ri->ri_flg & RI_BSWAP) != 0) {
220#endif
221		stamp[0] = bswap32(stamp[0]);
222		stamp[1] = bswap32(stamp[1]);
223		stamp[2] = bswap32(stamp[2]);
224	}
225
226	/*
227	 * XXX the wsdisplay_emulops interface seems a little deficient in
228	 * that there is no way to clear the *entire* screen. We provide a
229	 * workaround here: if the entire console area is being cleared, and
230	 * the RI_FULLCLEAR flag is set, clear the entire display.
231	 */
232	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
233		stride = ri->ri_stride;
234		num = ri->ri_height;
235		rp = (uint32_t *)ri->ri_origbits;
236		if (ri->ri_hwbits)
237			hp = (uint32_t *)ri->ri_hworigbits;
238	} else {
239		stride = ri->ri_emustride;
240		num *= ri->ri_font->fontheight;
241		rp = (uint32_t *)(ri->ri_bits + row * ri->ri_yscale);
242		if (ri->ri_hwbits)
243			hp = (uint32_t *)(ri->ri_hwbits + row * ri->ri_yscale);
244	}
245
246	n9 = stride / (4 * 9);
247	cnt = n9 * (4 * 9);
248	n3 = (stride - cnt) / (4 * 3);
249	cnt += n3 * (4 * 3);
250	n1 = (stride - cnt) / 4;
251
252	while (num--) {
253		dp = rp;
254		for (cnt = n9; cnt; cnt--) {
255			dp[0] = stamp[0]; dp[1] = stamp[1]; dp[2] = stamp[2];
256			dp[3] = stamp[0]; dp[4] = stamp[1]; dp[5] = stamp[2];
257			dp[6] = stamp[0]; dp[7] = stamp[1]; dp[8] = stamp[2];
258			dp += 9;
259		}
260
261		for (cnt = n3; cnt; cnt--) {
262			dp[0] = stamp[0]; dp[1] = stamp[1]; dp[2] = stamp[2];
263			dp += 3;
264		}
265
266		for (cnt = 0; cnt < n1; cnt++)
267			*dp++ = stamp[cnt];
268
269		if (ri->ri_hwbits) {
270			memcpy(hp, rp, stride);
271			DELTA(hp, ri->ri_stride, uint32_t *);
272		}
273		DELTA(rp, ri->ri_stride, uint32_t *);
274	}
275}
276
277/*
278 * Erase columns.
279 */
280static void
281rasops24_erasecols(void *cookie, int row, int col, int num, long attr)
282{
283	struct rasops_info *ri = (struct rasops_info *)cookie;
284	int n12, n4, height, cnt, slop1, slop2, clr, stamp[3];
285	uint32_t *dp;
286	uint8_t *rp, *hp, *dbp;
287
288	hp = NULL;	/* XXX GCC */
289
290	/*
291	 * If the color is gray, we can cheat and use the generic routines
292	 * (which are faster, hopefully) since the r,g,b values are the same.
293	 */
294	if ((attr & WSATTR_PRIVATE2) != 0) {
295		rasops_erasecols(cookie, row, col, num, attr);
296		return;
297	}
298
299#ifdef RASOPS_CLIPPING
300	/* Catches 'row < 0' case too */
301	if ((unsigned)row >= (unsigned)ri->ri_rows)
302		return;
303
304	if (col < 0) {
305		num += col;
306		col = 0;
307	}
308
309	if (col + num > ri->ri_cols)
310		num = ri->ri_cols - col;
311
312	if (num <= 0)
313		return;
314#endif
315
316	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
317	if (ri->ri_hwbits)
318		hp = ri->ri_hwbits + row * ri->ri_yscale + col * ri->ri_xscale;
319
320	num *= ri->ri_font->fontwidth;
321	height = ri->ri_font->fontheight;
322
323	clr = ri->ri_devcmap[((uint32_t)attr >> 16) & 0xf] & 0xffffff;
324	stamp[0] = (clr <<  8) | (clr >> 16);
325	stamp[1] = (clr << 16) | (clr >>  8);
326	stamp[2] = (clr << 24) |  clr;
327
328#if BYTE_ORDER == LITTLE_ENDIAN
329	if ((ri->ri_flg & RI_BSWAP) == 0) {
330#else
331	if ((ri->ri_flg & RI_BSWAP) != 0) {
332#endif
333		stamp[0] = bswap32(stamp[0]);
334		stamp[1] = bswap32(stamp[1]);
335		stamp[2] = bswap32(stamp[2]);
336	}
337
338	/*
339	 * The current byte offset mod 4 tells us the number of 24-bit pels
340	 * we need to write for alignment to 32-bits. Once we're aligned on
341	 * a 32-bit boundary, we're also aligned on a 4 pixel boundary, so
342	 * the stamp does not need to be rotated. The following shows the
343	 * layout of 4 pels in a 3 word region and illustrates this:
344	 *
345	 *	aaab bbcc cddd
346	 */
347	slop1 = (uintptr_t)rp & 3;
348	cnt = slop1;
349	n12 = (num - cnt) / 12;
350	cnt += n12 * 12;
351	n4 = (num - cnt) / 4;
352	cnt += n4 * 4;
353	slop2 = num - cnt;
354
355	while (height--) {
356		dbp = rp;
357
358		/* Align to 4 bytes */
359		/* XXX handle with masks, bring under control of RI_BSWAP */
360		for (cnt = slop1; cnt; cnt--) {
361			*dbp++ = (clr >> 16);
362			*dbp++ = (clr >> 8);
363			*dbp++ =  clr;
364		}
365
366		dp = (uint32_t *)dbp;
367
368		/* 12 pels per loop */
369		for (cnt = n12; cnt; cnt--) {
370			dp[0] = stamp[0]; dp[1] = stamp[1]; dp[2] = stamp[2];
371			dp[3] = stamp[0]; dp[4] = stamp[1]; dp[5] = stamp[2];
372			dp[6] = stamp[0]; dp[7] = stamp[1]; dp[8] = stamp[2];
373			dp += 9;
374		}
375
376		/* 4 pels per loop */
377		for (cnt = n4; cnt; cnt--) {
378			dp[0] = stamp[0]; dp[1] = stamp[1]; dp[2] = stamp[2];
379			dp += 3;
380		}
381
382		/* Trailing slop */
383		/* XXX handle with masks, bring under control of RI_BSWAP */
384		dbp = (uint8_t *)dp;
385		for (cnt = slop2; cnt; cnt--) {
386			*dbp++ = (clr >> 16);
387			*dbp++ = (clr >> 8);
388			*dbp++ =  clr;
389		}
390
391		if (ri->ri_hwbits) {
392			memcpy(hp, rp, num * 3);
393			hp += ri->ri_stride;
394		}
395		rp += ri->ri_stride;
396	}
397}
398