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