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