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