1/*	$OpenBSD: rasops24.c,v 1.13 2023/01/18 11:08:49 nicm Exp $	*/
2/*	$NetBSD: rasops24.c,v 1.12 2000/04/12 14:22:29 pk Exp $	*/
3
4/*-
5 * Copyright (c) 1999 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Andrew Doran.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/time.h>
36#include <sys/endian.h>
37
38#include <dev/wscons/wsdisplayvar.h>
39#include <dev/wscons/wsconsio.h>
40#include <dev/rasops/rasops.h>
41
42int 	rasops24_putchar(void *, int, int, u_int, uint32_t attr);
43#ifndef RASOPS_SMALL
44int 	rasops24_putchar8(void *, int, int, u_int, uint32_t attr);
45int 	rasops24_putchar12(void *, int, int, u_int, uint32_t attr);
46int 	rasops24_putchar16(void *, int, int, u_int, uint32_t attr);
47void	rasops24_makestamp(struct rasops_info *, uint32_t);
48
49/*
50 * 4x1 stamp for optimized character blitting
51 */
52static int32_t	stamp[64];
53static uint32_t	stamp_attr;
54static int	stamp_mutex;	/* XXX see note in readme */
55#endif
56
57/*
58 * XXX this confuses the hell out of gcc2 (not egcs) which always insists
59 * that the shift count is negative.
60 *
61 * offset = STAMP_SHIFT(fontbits, nibble #) & STAMP_MASK
62 * destination int32_t[0] = STAMP_READ(offset)
63 * destination int32_t[1] = STAMP_READ(offset + 4)
64 * destination int32_t[2] = STAMP_READ(offset + 8)
65 */
66#define STAMP_SHIFT(fb,n)	((n*4-4) >= 0 ? (fb)>>(n*4-4):(fb)<<-(n*4-4))
67#define STAMP_MASK		(0xf << 4)
68#define STAMP_READ(o)		(*(int32_t *)((caddr_t)stamp + (o)))
69
70/*
71 * Initialize rasops_info struct for this colordepth.
72 */
73void
74rasops24_init(struct rasops_info *ri)
75{
76
77	switch (ri->ri_font->fontwidth) {
78#ifndef RASOPS_SMALL
79	case 8:
80		ri->ri_ops.putchar = rasops24_putchar8;
81		break;
82	case 12:
83		ri->ri_ops.putchar = rasops24_putchar12;
84		break;
85	case 16:
86		ri->ri_ops.putchar = rasops24_putchar16;
87		break;
88#endif
89	default:
90		ri->ri_ops.putchar = rasops24_putchar;
91		break;
92	}
93
94	if (ri->ri_rnum == 0) {
95		ri->ri_rnum = 8;
96		ri->ri_rpos = 0;
97		ri->ri_gnum = 8;
98		ri->ri_gpos = 8;
99		ri->ri_bnum = 8;
100		ri->ri_bpos = 16;
101	}
102}
103
104/*
105 * Put a single character. This is the generic version.
106 * XXX this bites - we should use masks.
107 */
108int
109rasops24_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr)
110{
111	int fb, width, height, cnt, clr[2];
112	struct rasops_info *ri;
113	u_char *dp, *rp, *fr;
114
115	ri = (struct rasops_info *)cookie;
116
117#ifdef RASOPS_CLIPPING
118	/* Catches 'row < 0' case too */
119	if ((unsigned)row >= (unsigned)ri->ri_rows)
120		return 0;
121
122	if ((unsigned)col >= (unsigned)ri->ri_cols)
123		return 0;
124#endif
125
126	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
127	height = ri->ri_font->fontheight;
128	width = ri->ri_font->fontwidth;
129
130	clr[1] = ri->ri_devcmap[((u_int)attr >> 24) & 0xf];
131	clr[0] = ri->ri_devcmap[((u_int)attr >> 16) & 0xf];
132
133	if (uc == ' ') {
134		while (height--) {
135			dp = rp;
136			rp += ri->ri_stride;
137
138			for (cnt = width; cnt; cnt--) {
139				*dp++ = clr[0] >> 16;
140				*dp++ = clr[0] >> 8;
141				*dp++ = clr[0];
142			}
143		}
144	} else {
145		uc -= ri->ri_font->firstchar;
146		fr = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
147
148		while (height--) {
149			dp = rp;
150			fb = fr[3] | (fr[2] << 8) | (fr[1] << 16) |
151			    (fr[0] << 24);
152			fr += ri->ri_font->stride;
153			rp += ri->ri_stride;
154
155			for (cnt = width; cnt; cnt--, fb <<= 1) {
156				if ((fb >> 31) & 1) {
157					*dp++ = clr[1] >> 16;
158					*dp++ = clr[1] >> 8;
159					*dp++ = clr[1];
160				} else {
161					*dp++ = clr[0] >> 16;
162					*dp++ = clr[0] >> 8;
163					*dp++ = clr[0];
164				}
165			}
166		}
167	}
168
169	/* Do underline */
170	if ((attr & WSATTR_UNDERLINE) != 0) {
171		rp -= ri->ri_stride << 1;
172
173		while (width--) {
174			*rp++ = clr[1] >> 16;
175			*rp++ = clr[1] >> 8;
176			*rp++ = clr[1];
177		}
178	}
179
180	return 0;
181}
182
183#ifndef RASOPS_SMALL
184/*
185 * Recompute the blitting stamp.
186 */
187void
188rasops24_makestamp(struct rasops_info *ri, uint32_t attr)
189{
190	u_int fg, bg, c1, c2, c3, c4;
191	int i;
192
193	fg = ri->ri_devcmap[((u_int)attr >> 24) & 0xf] & 0xffffff;
194	bg = ri->ri_devcmap[((u_int)attr >> 16) & 0xf] & 0xffffff;
195	stamp_attr = attr;
196
197	for (i = 0; i < 64; i += 4) {
198#if BYTE_ORDER == LITTLE_ENDIAN
199		c1 = (i & 32 ? fg : bg);
200		c2 = (i & 16 ? fg : bg);
201		c3 = (i & 8 ? fg : bg);
202		c4 = (i & 4 ? fg : bg);
203#else
204		c1 = (i & 8 ? fg : bg);
205		c2 = (i & 4 ? fg : bg);
206		c3 = (i & 16 ? fg : bg);
207		c4 = (i & 32 ? fg : bg);
208#endif
209		stamp[i+0] = (c1 <<  8) | (c2 >> 16);
210		stamp[i+1] = (c2 << 16) | (c3 >>  8);
211		stamp[i+2] = (c3 << 24) | c4;
212
213#if BYTE_ORDER == LITTLE_ENDIAN
214		if ((ri->ri_flg & RI_BSWAP) == 0) {
215#else
216		if ((ri->ri_flg & RI_BSWAP) != 0) {
217#endif
218			stamp[i+0] = swap32(stamp[i+0]);
219			stamp[i+1] = swap32(stamp[i+1]);
220			stamp[i+2] = swap32(stamp[i+2]);
221		}
222	}
223}
224
225/*
226 * Put a single character. This is for 8-pixel wide fonts.
227 */
228int
229rasops24_putchar8(void *cookie, int row, int col, u_int uc, uint32_t attr)
230{
231	struct rasops_info *ri;
232	int height, so, fs;
233	int32_t *rp;
234	u_char *fr;
235
236	/* Can't risk remaking the stamp if it's already in use */
237	if (stamp_mutex++) {
238		stamp_mutex--;
239		return rasops24_putchar(cookie, row, col, uc, attr);
240	}
241
242	ri = (struct rasops_info *)cookie;
243
244#ifdef RASOPS_CLIPPING
245	if ((unsigned)row >= (unsigned)ri->ri_rows) {
246		stamp_mutex--;
247		return 0;
248	}
249
250	if ((unsigned)col >= (unsigned)ri->ri_cols) {
251		stamp_mutex--;
252		return 0;
253	}
254#endif
255
256	/* Recompute stamp? */
257	if (attr != stamp_attr)
258		rasops24_makestamp(ri, attr);
259
260	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
261	height = ri->ri_font->fontheight;
262
263	if (uc == (u_int)-1) {
264		int32_t c = stamp[0];
265		while (height--) {
266			rp[0] = rp[1] = rp[2] = rp[3] = rp[4] = rp[5] = c;
267			DELTA(rp, ri->ri_stride, int32_t *);
268		}
269	} else {
270		uc -= ri->ri_font->firstchar;
271		fr = (u_char *)ri->ri_font->data + uc*ri->ri_fontscale;
272		fs = ri->ri_font->stride;
273
274		while (height--) {
275			so = STAMP_SHIFT(fr[0], 1) & STAMP_MASK;
276			rp[0] = STAMP_READ(so);
277			rp[1] = STAMP_READ(so + 4);
278			rp[2] = STAMP_READ(so + 8);
279
280			so = STAMP_SHIFT(fr[0], 0) & STAMP_MASK;
281			rp[3] = STAMP_READ(so);
282			rp[4] = STAMP_READ(so + 4);
283			rp[5] = STAMP_READ(so + 8);
284
285			fr += fs;
286			DELTA(rp, ri->ri_stride, int32_t *);
287		}
288	}
289
290	/* Do underline */
291	if ((attr & WSATTR_UNDERLINE) != 0) {
292		int32_t c = STAMP_READ(52);
293
294		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
295		rp[0] = rp[1] = rp[2] = rp[3] = rp[4] = rp[5] = c;
296	}
297
298	stamp_mutex--;
299
300	return 0;
301}
302
303/*
304 * Put a single character. This is for 12-pixel wide fonts.
305 */
306int
307rasops24_putchar12(void *cookie, int row, int col, u_int uc, uint32_t attr)
308{
309	struct rasops_info *ri;
310	int height, so, fs;
311	int32_t *rp;
312	u_char *fr;
313
314	/* Can't risk remaking the stamp if it's already in use */
315	if (stamp_mutex++) {
316		stamp_mutex--;
317		return rasops24_putchar(cookie, row, col, uc, attr);
318	}
319
320	ri = (struct rasops_info *)cookie;
321
322#ifdef RASOPS_CLIPPING
323	if ((unsigned)row >= (unsigned)ri->ri_rows) {
324		stamp_mutex--;
325		return 0;
326	}
327
328	if ((unsigned)col >= (unsigned)ri->ri_cols) {
329		stamp_mutex--;
330		return 0;
331	}
332#endif
333
334	/* Recompute stamp? */
335	if (attr != stamp_attr)
336		rasops24_makestamp(ri, attr);
337
338	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
339	height = ri->ri_font->fontheight;
340
341	if (uc == (u_int)-1) {
342		int32_t c = stamp[0];
343		while (height--) {
344			rp[0] = rp[1] = rp[2] = rp[3] =
345			rp[4] = rp[5] = rp[6] = rp[7] = rp[8] = c;
346			DELTA(rp, ri->ri_stride, int32_t *);
347		}
348	} else {
349		uc -= ri->ri_font->firstchar;
350		fr = (u_char *)ri->ri_font->data + uc*ri->ri_fontscale;
351		fs = ri->ri_font->stride;
352
353		while (height--) {
354			so = STAMP_SHIFT(fr[0], 1) & STAMP_MASK;
355			rp[0] = STAMP_READ(so);
356			rp[1] = STAMP_READ(so + 4);
357			rp[2] = STAMP_READ(so + 8);
358
359			so = STAMP_SHIFT(fr[0], 0) & STAMP_MASK;
360			rp[3] = STAMP_READ(so);
361			rp[4] = STAMP_READ(so + 4);
362			rp[5] = STAMP_READ(so + 8);
363
364			so = STAMP_SHIFT(fr[1], 1) & STAMP_MASK;
365			rp[6] = STAMP_READ(so);
366			rp[7] = STAMP_READ(so + 4);
367			rp[8] = STAMP_READ(so + 8);
368
369			fr += fs;
370			DELTA(rp, ri->ri_stride, int32_t *);
371		}
372	}
373
374	/* Do underline */
375	if ((attr & WSATTR_UNDERLINE) != 0) {
376		int32_t c = STAMP_READ(52);
377
378		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
379		rp[0] = rp[1] = rp[2] = rp[3] =
380		rp[4] = rp[5] = rp[6] = rp[7] = rp[8] = c;
381	}
382
383	stamp_mutex--;
384
385	return 0;
386}
387
388/*
389 * Put a single character. This is for 16-pixel wide fonts.
390 */
391int
392rasops24_putchar16(void *cookie, int row, int col, u_int uc, uint32_t attr)
393{
394	struct rasops_info *ri;
395	int height, so, fs;
396	int32_t *rp;
397	u_char *fr;
398
399	/* Can't risk remaking the stamp if it's already in use */
400	if (stamp_mutex++) {
401		stamp_mutex--;
402		return rasops24_putchar(cookie, row, col, uc, attr);
403	}
404
405	ri = (struct rasops_info *)cookie;
406
407#ifdef RASOPS_CLIPPING
408	if ((unsigned)row >= (unsigned)ri->ri_rows) {
409		stamp_mutex--;
410		return 0;
411	}
412
413	if ((unsigned)col >= (unsigned)ri->ri_cols) {
414		stamp_mutex--;
415		return 0;
416	}
417#endif
418
419	/* Recompute stamp? */
420	if (attr != stamp_attr)
421		rasops24_makestamp(ri, attr);
422
423	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
424	height = ri->ri_font->fontheight;
425
426	if (uc == (u_int)-1) {
427		int32_t c = stamp[0];
428		while (height--) {
429			rp[0] = rp[1] = rp[2] = rp[3] =
430			rp[4] = rp[5] = rp[6] = rp[7] =
431			rp[8] = rp[9] = rp[10] = rp[11] = c;
432			DELTA(rp, ri->ri_stride, int32_t *);
433		}
434	} else {
435		uc -= ri->ri_font->firstchar;
436		fr = (u_char *)ri->ri_font->data + uc*ri->ri_fontscale;
437		fs = ri->ri_font->stride;
438
439		while (height--) {
440			so = STAMP_SHIFT(fr[0], 1) & STAMP_MASK;
441			rp[0] = STAMP_READ(so);
442			rp[1] = STAMP_READ(so + 4);
443			rp[2] = STAMP_READ(so + 8);
444
445			so = STAMP_SHIFT(fr[0], 0) & STAMP_MASK;
446			rp[3] = STAMP_READ(so);
447			rp[4] = STAMP_READ(so + 4);
448			rp[5] = STAMP_READ(so + 8);
449
450			so = STAMP_SHIFT(fr[1], 1) & STAMP_MASK;
451			rp[6] = STAMP_READ(so);
452			rp[7] = STAMP_READ(so + 4);
453			rp[8] = STAMP_READ(so + 8);
454
455			so = STAMP_SHIFT(fr[1], 0) & STAMP_MASK;
456			rp[9] = STAMP_READ(so);
457			rp[10] = STAMP_READ(so + 4);
458			rp[11] = STAMP_READ(so + 8);
459
460			DELTA(rp, ri->ri_stride, int32_t *);
461			fr += fs;
462		}
463	}
464
465	/* Do underline */
466	if ((attr & WSATTR_UNDERLINE) != 0) {
467		int32_t c = STAMP_READ(52);
468
469		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
470		rp[0] = rp[1] = rp[2] = rp[3] =
471		rp[4] = rp[5] = rp[6] = rp[7] =
472		rp[8] = rp[9] = rp[10] = rp[11] = c;
473	}
474
475	stamp_mutex--;
476
477	return 0;
478}
479#endif	/* !RASOPS_SMALL */
480