rasops24.c revision 1.48
1/* 	$NetBSD: rasops24.c,v 1.48 2019/08/07 12:33:48 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.48 2019/08/07 12:33:48 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#define	RASOPS_DEPTH	24
49#include <dev/rasops/rasops.h>
50
51static void 	rasops24_erasecols(void *, int, int, int, long);
52static void 	rasops24_eraserows(void *, int, int, long);
53static void 	rasops24_putchar(void *, int, int, u_int, long);
54static void 	rasops24_putchar_aa(void *, int, int, u_int, long);
55static __inline void
56		rasops24_makestamp1(struct rasops_info *, uint32_t *,
57				    uint32_t, uint32_t, uint32_t, uint32_t);
58#ifndef RASOPS_SMALL
59static void 	rasops24_putchar8(void *, int, int, u_int, long);
60static void 	rasops24_putchar12(void *, int, int, u_int, long);
61static void 	rasops24_putchar16(void *, int, int, u_int, long);
62static void	rasops24_makestamp(struct rasops_info *, long);
63#endif
64
65#ifndef RASOPS_SMALL
66/* 4x1 stamp for optimized character blitting */
67static uint32_t			stamp[64];
68static long			stamp_attr;
69static struct rasops_info	*stamp_ri;
70
71/*
72 * offset = STAMP_SHIFT(fontbits, nibble #) & STAMP_MASK
73 * destination uint32_t[0] = STAMP_READ(offset)
74 * destination uint32_t[1] = STAMP_READ(offset + 4)
75 * destination uint32_t[2] = STAMP_READ(offset + 8)
76 */
77#define	STAMP_SHIFT(fb, n)	((n) ? (fb) : (fb) << 4)
78#define	STAMP_MASK		(0xf << 4)
79#define	STAMP_READ(o)		(*(uint32_t *)((uint8_t *)stamp + (o)))
80#endif
81
82/*
83 * Initialize rasops_info struct for this colordepth.
84 */
85void
86rasops24_init(struct rasops_info *ri)
87{
88
89	if (ri->ri_rnum == 0) {
90		ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
91
92		ri->ri_rpos = 0;
93		ri->ri_gpos = 8;
94		ri->ri_bpos = 16;
95	}
96
97	ri->ri_ops.erasecols = rasops24_erasecols;
98	ri->ri_ops.eraserows = rasops24_eraserows;
99
100	if (FONT_IS_ALPHA(ri->ri_font)) {
101		ri->ri_ops.putchar = rasops24_putchar_aa;
102		return;
103	}
104
105	switch (ri->ri_font->fontwidth) {
106#ifndef RASOPS_SMALL
107	case 8:
108		ri->ri_ops.putchar = rasops24_putchar8;
109		break;
110	case 12:
111		ri->ri_ops.putchar = rasops24_putchar12;
112		break;
113	case 16:
114		ri->ri_ops.putchar = rasops24_putchar16;
115		break;
116#endif
117	default:
118		ri->ri_ops.putchar = rasops24_putchar;
119		return;
120	}
121
122#ifndef RASOPS_SMALL
123	stamp_attr = 0;
124	stamp_ri = NULL;
125#endif
126}
127
128#undef	RASOPS_AA
129#include "rasops_putchar.h"
130
131#define	RASOPS_AA
132#include "rasops_putchar.h"
133#undef	RASOPS_AA
134
135static __inline void
136rasops24_makestamp1(struct rasops_info *ri, uint32_t *xstamp,
137    uint32_t c1, uint32_t c2, uint32_t c3, uint32_t c4)
138{
139
140	xstamp[0] = (c1 <<  8) | (c2 >> 16);
141	xstamp[1] = (c2 << 16) | (c3 >>  8);
142	xstamp[2] = (c3 << 24) |  c4;
143
144#if BYTE_ORDER == LITTLE_ENDIAN
145	if ((ri->ri_flg & RI_BSWAP) == 0)
146#else
147	if ((ri->ri_flg & RI_BSWAP) != 0)
148#endif
149	{
150		xstamp[0] = bswap32(xstamp[0]);
151		xstamp[1] = bswap32(xstamp[1]);
152		xstamp[2] = bswap32(xstamp[2]);
153	}
154}
155
156#ifndef RASOPS_SMALL
157/*
158 * Recompute the blitting stamp.
159 */
160static void
161rasops24_makestamp(struct rasops_info *ri, long attr)
162{
163	uint32_t fg, bg, c1, c2, c3, c4;
164	int i;
165
166	stamp_attr = attr;
167	stamp_ri = ri;
168
169	fg = ri->ri_devcmap[((uint32_t)attr >> 24) & 0xf] & 0xffffff;
170	bg = ri->ri_devcmap[((uint32_t)attr >> 16) & 0xf] & 0xffffff;
171
172	for (i = 0; i < 64; i += 4) {
173#if BYTE_ORDER == LITTLE_ENDIAN
174		c1 = i & 32 ? fg : bg;
175		c2 = i & 16 ? fg : bg;
176		c3 = i &  8 ? fg : bg;
177		c4 = i &  4 ? fg : bg;
178#else
179		c1 = i &  8 ? fg : bg;
180		c2 = i &  4 ? fg : bg;
181		c3 = i & 16 ? fg : bg;
182		c4 = i & 32 ? fg : bg;
183#endif
184		rasops24_makestamp1(ri, &stamp[i], c1, c2, c3, c4);
185	}
186}
187
188#define	RASOPS_WIDTH	8
189#include "rasops_putchar_width.h"
190#undef	RASOPS_WIDTH
191
192#define	RASOPS_WIDTH	12
193#include "rasops_putchar_width.h"
194#undef	RASOPS_WIDTH
195
196#define	RASOPS_WIDTH	16
197#include "rasops_putchar_width.h"
198#undef	RASOPS_WIDTH
199
200#endif	/* !RASOPS_SMALL */
201
202/*
203 * Erase rows. This is nice and easy due to alignment.
204 */
205static void
206rasops24_eraserows(void *cookie, int row, int num, long attr)
207{
208	struct rasops_info *ri = (struct rasops_info *)cookie;
209	int full, slop, cnt, stride;
210	uint32_t *rp, *dp, *hp, clr, xstamp[3];
211
212	hp = NULL;	/* XXX GCC */
213
214	/*
215	 * If the color is gray, we can cheat and use the generic routines
216	 * (which are faster, hopefully) since the r,g,b values are the same.
217	 */
218	if ((attr & WSATTR_PRIVATE2) != 0) {
219		rasops_eraserows(cookie, row, num, attr);
220		return;
221	}
222
223#ifdef RASOPS_CLIPPING
224	if (row < 0) {
225		num += row;
226		row = 0;
227	}
228
229	if (row + num > ri->ri_rows)
230		num = ri->ri_rows - row;
231
232	if (num <= 0)
233		return;
234#endif
235
236	clr = ri->ri_devcmap[((uint32_t)attr >> 16) & 0xf] & 0xffffff;
237	rasops24_makestamp1(ri, xstamp, clr, clr, clr, clr);
238
239	/*
240	 * XXX the wsdisplay_emulops interface seems a little deficient in
241	 * that there is no way to clear the *entire* screen. We provide a
242	 * workaround here: if the entire console area is being cleared, and
243	 * the RI_FULLCLEAR flag is set, clear the entire display.
244	 */
245	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
246		stride = ri->ri_stride;
247		num = ri->ri_height;
248		rp = (uint32_t *)ri->ri_origbits;
249		if (ri->ri_hwbits)
250			hp = (uint32_t *)ri->ri_hworigbits;
251	} else {
252		stride = ri->ri_emustride;
253		num *= ri->ri_font->fontheight;
254		rp = (uint32_t *)(ri->ri_bits + row * ri->ri_yscale);
255		if (ri->ri_hwbits)
256			hp = (uint32_t *)(ri->ri_hwbits + row * ri->ri_yscale);
257	}
258
259	full = stride / (4 * 3);
260	slop = (stride - full * (4 * 3)) / 4;
261
262	while (num--) {
263		dp = rp;
264		for (cnt = full; cnt; cnt--) {
265			dp[0] = xstamp[0];
266			dp[1] = xstamp[1];
267			dp[2] = xstamp[2];
268			dp += 3;
269		}
270		for (cnt = 0; cnt < slop; cnt++)
271			*dp++ = xstamp[cnt];
272
273		if (ri->ri_hwbits) {
274			memcpy(hp, rp, stride);
275			DELTA(hp, ri->ri_stride, uint32_t *);
276		}
277
278		DELTA(rp, ri->ri_stride, uint32_t *);
279	}
280}
281
282/*
283 * Erase columns.
284 */
285static void
286rasops24_erasecols(void *cookie, int row, int col, int num, long attr)
287{
288	struct rasops_info *ri = (struct rasops_info *)cookie;
289	int height, cnt, slop1, slop2, full;
290	uint32_t clr, xstamp[3], *dp;
291	uint8_t *rp, *hp, *dbp;
292
293	hp = NULL;	/* XXX GCC */
294
295	/*
296	 * If the color is gray, we can cheat and use the generic routines
297	 * (which are faster, hopefully) since the r,g,b values are the same.
298	 */
299	if ((attr & WSATTR_PRIVATE2) != 0) {
300		rasops_erasecols(cookie, row, col, num, attr);
301		return;
302	}
303
304#ifdef RASOPS_CLIPPING
305	/* Catches 'row < 0' case too */
306	if ((unsigned)row >= (unsigned)ri->ri_rows)
307		return;
308
309	if (col < 0) {
310		num += col;
311		col = 0;
312	}
313
314	if (col + num > ri->ri_cols)
315		num = ri->ri_cols - col;
316
317	if (num <= 0)
318		return;
319#endif
320
321	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
322	if (ri->ri_hwbits)
323		hp = ri->ri_hwbits + row * ri->ri_yscale + col * ri->ri_xscale;
324
325	num *= ri->ri_xscale;
326	height = ri->ri_font->fontheight;
327
328	clr = ri->ri_devcmap[((uint32_t)attr >> 16) & 0xf] & 0xffffff;
329	rasops24_makestamp1(ri, xstamp, clr, clr, clr, clr);
330
331	/*
332	 * Align to word boundary by 24-bit-wise operations:
333	 *
334	 * rp % 4 == 1 ---> slop1 = 3:
335	 *	0123
336	 *	-RGB
337	 *
338	 * rp % 4 == 2 ---> slop1 = 6:
339	 *	0123 0123
340	 *	--RG BRGB
341	 *
342	 * rp % 4 == 3 ---> slop1 = 9:
343	 *	0123 0123 0123
344	 *	---R GBRG BRGB
345	 */
346	slop1 = 3 * ((uintptr_t)rp % 4);
347	slop2 = (num - slop1) % 12;
348	full = (num - slop1 /* - slop2 */) / 12;
349
350	while (height--) {
351		/* Align to word boundary */
352		dbp = rp;
353		for (cnt = slop1; cnt; cnt -= 3) {
354			*dbp++ = (clr >> 16);
355			*dbp++ = (clr >> 8);
356			*dbp++ = clr;
357		}
358
359		/* 4 pels per loop */
360		dp = (uint32_t *)dbp;
361		for (cnt = full; cnt; cnt--) {
362			dp[0] = xstamp[0];
363			dp[1] = xstamp[1];
364			dp[2] = xstamp[2];
365			dp += 3;
366		}
367
368		/* Trailing slop */
369		dbp = (uint8_t *)dp;
370		for (cnt = slop2; cnt; cnt -= 3) {
371			*dbp++ = (clr >> 16);
372			*dbp++ = (clr >> 8);
373			*dbp++ = clr;
374		}
375
376		if (ri->ri_hwbits) {
377			memcpy(hp, rp, num);
378			hp += ri->ri_stride;
379		}
380
381		rp += ri->ri_stride;
382	}
383}
384