1 /* $NetBSD: rasops24.c,v 1.50 2019/08/14 00:51: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.50 2019/08/14 00:51:10 rin Exp $"); 34 35 #ifdef _KERNEL_OPT 36 #include "opt_rasops.h" 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/bswap.h> 41 42 #include <machine/endian.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 51 static void rasops24_erasecols(void *, int, int, int, long); 52 static void rasops24_eraserows(void *, int, int, long); 53 static void rasops24_putchar(void *, int, int, u_int, long); 54 static void rasops24_putchar_aa(void *, int, int, u_int, long); 55 static __inline void 56 rasops24_makestamp1(struct rasops_info *, uint32_t *, 57 uint32_t, uint32_t, uint32_t, uint32_t); 58 #ifndef RASOPS_SMALL 59 static void rasops24_putchar8(void *, int, int, u_int, long); 60 static void rasops24_putchar12(void *, int, int, u_int, long); 61 static void rasops24_putchar16(void *, int, int, u_int, long); 62 static void rasops24_makestamp(struct rasops_info *, long); 63 #endif 64 65 #ifndef RASOPS_SMALL 66 /* stamp for optimized character blitting */ 67 static uint32_t stamp[64]; 68 static long stamp_attr; 69 static 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 */ 85 void 86 rasops24_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 = -1; 124 stamp_ri = NULL; 125 #endif 126 } 127 128 /* rasops24_putchar */ 129 #undef RASOPS_AA 130 #include <dev/rasops/rasops_putchar.h> 131 132 /* rasops24_putchar_aa */ 133 #define RASOPS_AA 134 #include <dev/rasops/rasops_putchar.h> 135 #undef RASOPS_AA 136 137 static __inline void 138 rasops24_makestamp1(struct rasops_info *ri, uint32_t *xstamp, 139 uint32_t c1, uint32_t c2, uint32_t c3, uint32_t c4) 140 { 141 142 xstamp[0] = (c1 << 8) | (c2 >> 16); 143 xstamp[1] = (c2 << 16) | (c3 >> 8); 144 xstamp[2] = (c3 << 24) | c4; 145 146 #if BYTE_ORDER == LITTLE_ENDIAN 147 if ((ri->ri_flg & RI_BSWAP) == 0) 148 #else 149 if ((ri->ri_flg & RI_BSWAP) != 0) 150 #endif 151 { 152 xstamp[0] = bswap32(xstamp[0]); 153 xstamp[1] = bswap32(xstamp[1]); 154 xstamp[2] = bswap32(xstamp[2]); 155 } 156 } 157 158 #ifndef RASOPS_SMALL 159 /* 160 * Recompute the blitting stamp. 161 */ 162 static void 163 rasops24_makestamp(struct rasops_info *ri, long attr) 164 { 165 int i; 166 uint32_t bg, fg, c1, c2, c3, c4; 167 168 stamp_attr = attr; 169 stamp_ri = ri; 170 171 bg = ATTR_BG(ri, attr) & 0xffffff; 172 fg = ATTR_FG(ri, attr) & 0xffffff; 173 174 for (i = 0; i < 64; i += 4) { 175 #if BYTE_ORDER == LITTLE_ENDIAN 176 c1 = i & 32 ? fg : bg; 177 c2 = i & 16 ? fg : bg; 178 c3 = i & 8 ? fg : bg; 179 c4 = i & 4 ? fg : bg; 180 #else 181 c1 = i & 8 ? fg : bg; 182 c2 = i & 4 ? fg : bg; 183 c3 = i & 16 ? fg : bg; 184 c4 = i & 32 ? fg : bg; 185 #endif 186 rasops24_makestamp1(ri, &stamp[i], c1, c2, c3, c4); 187 } 188 } 189 190 /* 191 * Width-optimized putchar functions 192 */ 193 #define RASOPS_WIDTH 8 194 #include <dev/rasops/rasops_putchar_width.h> 195 #undef RASOPS_WIDTH 196 197 #define RASOPS_WIDTH 12 198 #include <dev/rasops/rasops_putchar_width.h> 199 #undef RASOPS_WIDTH 200 201 #define RASOPS_WIDTH 16 202 #include <dev/rasops/rasops_putchar_width.h> 203 #undef RASOPS_WIDTH 204 205 #endif /* !RASOPS_SMALL */ 206 207 /* 208 * Erase rows. This is nice and easy due to alignment. 209 */ 210 static void 211 rasops24_eraserows(void *cookie, int row, int num, long attr) 212 { 213 struct rasops_info *ri = (struct rasops_info *)cookie; 214 int bytes, full, slop, cnt; 215 uint32_t bg, xstamp[3]; 216 uint32_t *dp, *rp, *hp; 217 218 hp = NULL; /* XXX GCC */ 219 220 /* 221 * If the color is gray, we can cheat and use the generic routines 222 * (which are faster, hopefully) since the r,g,b values are the same. 223 */ 224 if ((attr & WSATTR_PRIVATE2) != 0) { 225 rasops_eraserows(cookie, row, num, attr); 226 return; 227 } 228 229 #ifdef RASOPS_CLIPPING 230 if (row < 0) { 231 num += row; 232 row = 0; 233 } 234 235 if (row + num > ri->ri_rows) 236 num = ri->ri_rows - row; 237 238 if (num <= 0) 239 return; 240 #endif 241 242 bg = ATTR_BG(ri, attr) & 0xffffff; 243 rasops24_makestamp1(ri, xstamp, bg, bg, bg, bg); 244 245 /* 246 * XXX the wsdisplay_emulops interface seems a little deficient in 247 * that there is no way to clear the *entire* screen. We provide a 248 * workaround here: if the entire console area is being cleared, and 249 * the RI_FULLCLEAR flag is set, clear the entire display. 250 */ 251 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 252 bytes = ri->ri_stride; 253 num = ri->ri_height; 254 rp = (uint32_t *)ri->ri_origbits; 255 if (ri->ri_hwbits) 256 hp = (uint32_t *)ri->ri_hworigbits; 257 } else { 258 bytes = ri->ri_emustride; 259 num *= ri->ri_font->fontheight; 260 rp = (uint32_t *)(ri->ri_bits + row * ri->ri_yscale); 261 if (ri->ri_hwbits) 262 hp = (uint32_t *)(ri->ri_hwbits + row * ri->ri_yscale); 263 } 264 265 full = bytes / (4 * 3); 266 slop = (bytes - full * (4 * 3)) / 4; 267 268 while (num--) { 269 dp = rp; 270 271 for (cnt = full; cnt; cnt--) { 272 dp[0] = xstamp[0]; 273 dp[1] = xstamp[1]; 274 dp[2] = xstamp[2]; 275 dp += 3; 276 } 277 278 for (cnt = 0; cnt < slop; cnt++) 279 *dp++ = xstamp[cnt]; 280 281 if (ri->ri_hwbits) { 282 memcpy(hp, rp, bytes); 283 DELTA(hp, ri->ri_stride, uint32_t *); 284 } 285 286 DELTA(rp, ri->ri_stride, uint32_t *); 287 } 288 } 289 290 /* 291 * Erase columns. 292 */ 293 static void 294 rasops24_erasecols(void *cookie, int row, int col, int num, long attr) 295 { 296 struct rasops_info *ri = (struct rasops_info *)cookie; 297 int height, slop1, slop2, full, cnt; 298 uint32_t bg, xstamp[3]; 299 uint32_t *dp; 300 uint8_t *bp, *rp, *hp; 301 302 hp = NULL; /* XXX GCC */ 303 304 /* 305 * If the color is gray, we can cheat and use the generic routines 306 * (which are faster, hopefully) since the r,g,b values are the same. 307 */ 308 if ((attr & WSATTR_PRIVATE2) != 0) { 309 rasops_erasecols(cookie, row, col, num, attr); 310 return; 311 } 312 313 #ifdef RASOPS_CLIPPING 314 /* Catches 'row < 0' case too */ 315 if ((unsigned)row >= (unsigned)ri->ri_rows) 316 return; 317 318 if (col < 0) { 319 num += col; 320 col = 0; 321 } 322 323 if (col + num > ri->ri_cols) 324 num = ri->ri_cols - col; 325 326 if (num <= 0) 327 return; 328 #endif 329 330 height = ri->ri_font->fontheight; 331 num *= ri->ri_xscale; 332 333 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 334 if (ri->ri_hwbits) 335 hp = ri->ri_hwbits + row * ri->ri_yscale + col * ri->ri_xscale; 336 337 bg = ATTR_BG(ri, attr) & 0xffffff; 338 rasops24_makestamp1(ri, xstamp, bg, bg, bg, bg); 339 340 /* 341 * Align to word boundary by 24-bit-wise operations: 342 * 343 * rp % 4 == 1 ---> slop1 = 3: 344 * 0123 345 * -RGB 346 * 347 * rp % 4 == 2 ---> slop1 = 6: 348 * 0123 0123 349 * --RG BRGB 350 * 351 * rp % 4 == 3 ---> slop1 = 9: 352 * 0123 0123 0123 353 * ---R GBRG BRGB 354 */ 355 slop1 = 3 * ((uintptr_t)rp % 4); 356 slop2 = (num - slop1) % 12; 357 full = (num - slop1 /* - slop2 */) / 12; 358 359 while (height--) { 360 /* Align to word boundary */ 361 bp = rp; 362 for (cnt = slop1; cnt; cnt -= 3) { 363 *bp++ = (bg >> 16); 364 *bp++ = (bg >> 8); 365 *bp++ = bg; 366 } 367 368 /* 4 pels per loop */ 369 dp = (uint32_t *)bp; 370 for (cnt = full; cnt; cnt--) { 371 dp[0] = xstamp[0]; 372 dp[1] = xstamp[1]; 373 dp[2] = xstamp[2]; 374 dp += 3; 375 } 376 377 /* Trailing slop */ 378 bp = (uint8_t *)dp; 379 for (cnt = slop2; cnt; cnt -= 3) { 380 *bp++ = (bg >> 16); 381 *bp++ = (bg >> 8); 382 *bp++ = bg; 383 } 384 385 if (ri->ri_hwbits) { 386 memcpy(hp, rp, num); 387 hp += ri->ri_stride; 388 } 389 390 rp += ri->ri_stride; 391 } 392 } 393