1 /* 2 * QEMU VGA Emulator templates 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #if DEPTH == 8 26 #define BPP 1 27 #define PIXEL_TYPE uint8_t 28 #elif DEPTH == 15 || DEPTH == 16 29 #define BPP 2 30 #define PIXEL_TYPE uint16_t 31 #elif DEPTH == 32 32 #define BPP 4 33 #define PIXEL_TYPE uint32_t 34 #else 35 #error unsupport depth 36 #endif 37 38 #ifdef BGR_FORMAT 39 #define PIXEL_NAME glue(DEPTH, bgr) 40 #else 41 #define PIXEL_NAME DEPTH 42 #endif /* BGR_FORMAT */ 43 44 #if DEPTH != 15 && !defined(BGR_FORMAT) 45 46 static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, 47 uint32_t font_data, 48 uint32_t xorcol, 49 uint32_t bgcol) 50 { 51 #if BPP == 1 52 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; 53 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; 54 #elif BPP == 2 55 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol; 56 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol; 57 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol; 58 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; 59 #else 60 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; 61 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; 62 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; 63 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; 64 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; 65 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; 66 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; 67 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; 68 #endif 69 } 70 71 static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, 72 const uint8_t *font_ptr, int h, 73 uint32_t fgcol, uint32_t bgcol) 74 { 75 uint32_t font_data, xorcol; 76 77 xorcol = bgcol ^ fgcol; 78 do { 79 font_data = font_ptr[0]; 80 glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol); 81 font_ptr += 4; 82 d += linesize; 83 } while (--h); 84 } 85 86 static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize, 87 const uint8_t *font_ptr, int h, 88 uint32_t fgcol, uint32_t bgcol) 89 { 90 uint32_t font_data, xorcol; 91 92 xorcol = bgcol ^ fgcol; 93 do { 94 font_data = font_ptr[0]; 95 glue(vga_draw_glyph_line_, DEPTH)(d, 96 expand4to8[font_data >> 4], 97 xorcol, bgcol); 98 glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP, 99 expand4to8[font_data & 0x0f], 100 xorcol, bgcol); 101 font_ptr += 4; 102 d += linesize; 103 } while (--h); 104 } 105 106 static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, 107 const uint8_t *font_ptr, int h, 108 uint32_t fgcol, uint32_t bgcol, int dup9) 109 { 110 uint32_t font_data, xorcol, v; 111 112 xorcol = bgcol ^ fgcol; 113 do { 114 font_data = font_ptr[0]; 115 #if BPP == 1 116 cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol); 117 v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; 118 cpu_to_32wu(((uint32_t *)d)+1, v); 119 if (dup9) 120 ((uint8_t *)d)[8] = v >> (24 * (1 - BIG)); 121 else 122 ((uint8_t *)d)[8] = bgcol; 123 124 #elif BPP == 2 125 cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol); 126 cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol); 127 cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol); 128 v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; 129 cpu_to_32wu(((uint32_t *)d)+3, v); 130 if (dup9) 131 ((uint16_t *)d)[8] = v >> (16 * (1 - BIG)); 132 else 133 ((uint16_t *)d)[8] = bgcol; 134 #else 135 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; 136 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; 137 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; 138 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; 139 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; 140 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; 141 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; 142 v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; 143 ((uint32_t *)d)[7] = v; 144 if (dup9) 145 ((uint32_t *)d)[8] = v; 146 else 147 ((uint32_t *)d)[8] = bgcol; 148 #endif 149 font_ptr += 4; 150 d += linesize; 151 } while (--h); 152 } 153 154 /* 155 * 4 color mode 156 */ 157 static void glue(vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d, 158 const uint8_t *s, int width) 159 { 160 uint32_t plane_mask, *palette, data, v; 161 int x; 162 163 palette = s1->last_palette; 164 plane_mask = mask16[s1->ar[0x12] & 0xf]; 165 width >>= 3; 166 for(x = 0; x < width; x++) { 167 data = ((uint32_t *)s)[0]; 168 data &= plane_mask; 169 v = expand2[GET_PLANE(data, 0)]; 170 v |= expand2[GET_PLANE(data, 2)] << 2; 171 ((PIXEL_TYPE *)d)[0] = palette[v >> 12]; 172 ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf]; 173 ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf]; 174 ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf]; 175 176 v = expand2[GET_PLANE(data, 1)]; 177 v |= expand2[GET_PLANE(data, 3)] << 2; 178 ((PIXEL_TYPE *)d)[4] = palette[v >> 12]; 179 ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf]; 180 ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf]; 181 ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf]; 182 d += BPP * 8; 183 s += 4; 184 } 185 } 186 187 #if BPP == 1 188 #define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v) 189 #elif BPP == 2 190 #define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v) 191 #else 192 #define PUT_PIXEL2(d, n, v) \ 193 ((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v) 194 #endif 195 196 /* 197 * 4 color mode, dup2 horizontal 198 */ 199 static void glue(vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d, 200 const uint8_t *s, int width) 201 { 202 uint32_t plane_mask, *palette, data, v; 203 int x; 204 205 palette = s1->last_palette; 206 plane_mask = mask16[s1->ar[0x12] & 0xf]; 207 width >>= 3; 208 for(x = 0; x < width; x++) { 209 data = ((uint32_t *)s)[0]; 210 data &= plane_mask; 211 v = expand2[GET_PLANE(data, 0)]; 212 v |= expand2[GET_PLANE(data, 2)] << 2; 213 PUT_PIXEL2(d, 0, palette[v >> 12]); 214 PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]); 215 PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]); 216 PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]); 217 218 v = expand2[GET_PLANE(data, 1)]; 219 v |= expand2[GET_PLANE(data, 3)] << 2; 220 PUT_PIXEL2(d, 4, palette[v >> 12]); 221 PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); 222 PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); 223 PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); 224 d += BPP * 16; 225 s += 4; 226 } 227 } 228 229 /* 230 * 16 color mode 231 */ 232 static void glue(vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d, 233 const uint8_t *s, int width) 234 { 235 uint32_t plane_mask, data, v, *palette; 236 int x; 237 238 palette = s1->last_palette; 239 plane_mask = mask16[s1->ar[0x12] & 0xf]; 240 width >>= 3; 241 for(x = 0; x < width; x++) { 242 data = ((uint32_t *)s)[0]; 243 data &= plane_mask; 244 v = expand4[GET_PLANE(data, 0)]; 245 v |= expand4[GET_PLANE(data, 1)] << 1; 246 v |= expand4[GET_PLANE(data, 2)] << 2; 247 v |= expand4[GET_PLANE(data, 3)] << 3; 248 ((PIXEL_TYPE *)d)[0] = palette[v >> 28]; 249 ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf]; 250 ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf]; 251 ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf]; 252 ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf]; 253 ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf]; 254 ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf]; 255 ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf]; 256 d += BPP * 8; 257 s += 4; 258 } 259 } 260 261 /* 262 * 16 color mode, dup2 horizontal 263 */ 264 static void glue(vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d, 265 const uint8_t *s, int width) 266 { 267 uint32_t plane_mask, data, v, *palette; 268 int x; 269 270 palette = s1->last_palette; 271 plane_mask = mask16[s1->ar[0x12] & 0xf]; 272 width >>= 3; 273 for(x = 0; x < width; x++) { 274 data = ((uint32_t *)s)[0]; 275 data &= plane_mask; 276 v = expand4[GET_PLANE(data, 0)]; 277 v |= expand4[GET_PLANE(data, 1)] << 1; 278 v |= expand4[GET_PLANE(data, 2)] << 2; 279 v |= expand4[GET_PLANE(data, 3)] << 3; 280 PUT_PIXEL2(d, 0, palette[v >> 28]); 281 PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]); 282 PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]); 283 PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]); 284 PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]); 285 PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); 286 PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); 287 PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); 288 d += BPP * 16; 289 s += 4; 290 } 291 } 292 293 /* 294 * 256 color mode, double pixels 295 * 296 * XXX: add plane_mask support (never used in standard VGA modes) 297 */ 298 static void glue(vga_draw_line8d2_, DEPTH)(VGACommonState *s1, uint8_t *d, 299 const uint8_t *s, int width) 300 { 301 uint32_t *palette; 302 int x; 303 304 palette = s1->last_palette; 305 width >>= 3; 306 for(x = 0; x < width; x++) { 307 PUT_PIXEL2(d, 0, palette[s[0]]); 308 PUT_PIXEL2(d, 1, palette[s[1]]); 309 PUT_PIXEL2(d, 2, palette[s[2]]); 310 PUT_PIXEL2(d, 3, palette[s[3]]); 311 d += BPP * 8; 312 s += 4; 313 } 314 } 315 316 /* 317 * standard 256 color mode 318 * 319 * XXX: add plane_mask support (never used in standard VGA modes) 320 */ 321 static void glue(vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d, 322 const uint8_t *s, int width) 323 { 324 uint32_t *palette; 325 int x; 326 327 palette = s1->last_palette; 328 width >>= 3; 329 for(x = 0; x < width; x++) { 330 ((PIXEL_TYPE *)d)[0] = palette[s[0]]; 331 ((PIXEL_TYPE *)d)[1] = palette[s[1]]; 332 ((PIXEL_TYPE *)d)[2] = palette[s[2]]; 333 ((PIXEL_TYPE *)d)[3] = palette[s[3]]; 334 ((PIXEL_TYPE *)d)[4] = palette[s[4]]; 335 ((PIXEL_TYPE *)d)[5] = palette[s[5]]; 336 ((PIXEL_TYPE *)d)[6] = palette[s[6]]; 337 ((PIXEL_TYPE *)d)[7] = palette[s[7]]; 338 d += BPP * 8; 339 s += 8; 340 } 341 } 342 343 void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, 344 const uint8_t *src1, 345 int poffset, int w, 346 unsigned int color0, 347 unsigned int color1, 348 unsigned int color_xor) 349 { 350 const uint8_t *plane0, *plane1; 351 int x, b0, b1; 352 uint8_t *d; 353 354 d = d1; 355 plane0 = src1; 356 plane1 = src1 + poffset; 357 for(x = 0; x < w; x++) { 358 b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1; 359 b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1; 360 #if DEPTH == 8 361 switch(b0 | (b1 << 1)) { 362 case 0: 363 break; 364 case 1: 365 d[0] ^= color_xor; 366 break; 367 case 2: 368 d[0] = color0; 369 break; 370 case 3: 371 d[0] = color1; 372 break; 373 } 374 #elif DEPTH == 16 375 switch(b0 | (b1 << 1)) { 376 case 0: 377 break; 378 case 1: 379 ((uint16_t *)d)[0] ^= color_xor; 380 break; 381 case 2: 382 ((uint16_t *)d)[0] = color0; 383 break; 384 case 3: 385 ((uint16_t *)d)[0] = color1; 386 break; 387 } 388 #elif DEPTH == 32 389 switch(b0 | (b1 << 1)) { 390 case 0: 391 break; 392 case 1: 393 ((uint32_t *)d)[0] ^= color_xor; 394 break; 395 case 2: 396 ((uint32_t *)d)[0] = color0; 397 break; 398 case 3: 399 ((uint32_t *)d)[0] = color1; 400 break; 401 } 402 #else 403 #error unsupported depth 404 #endif 405 d += BPP; 406 } 407 } 408 409 #endif /* DEPTH != 15 */ 410 411 412 /* XXX: optimize */ 413 414 /* 415 * 15 bit color 416 */ 417 static void glue(vga_draw_line15_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d, 418 const uint8_t *s, int width) 419 { 420 #if DEPTH == 15 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) 421 memcpy(d, s, width * 2); 422 #else 423 int w; 424 uint32_t v, r, g, b; 425 426 w = width; 427 do { 428 v = lduw_raw((void *)s); 429 r = (v >> 7) & 0xf8; 430 g = (v >> 2) & 0xf8; 431 b = (v << 3) & 0xf8; 432 ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); 433 s += 2; 434 d += BPP; 435 } while (--w != 0); 436 #endif 437 } 438 439 /* 440 * 16 bit color 441 */ 442 static void glue(vga_draw_line16_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d, 443 const uint8_t *s, int width) 444 { 445 #if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) 446 memcpy(d, s, width * 2); 447 #else 448 int w; 449 uint32_t v, r, g, b; 450 451 w = width; 452 do { 453 v = lduw_raw((void *)s); 454 r = (v >> 8) & 0xf8; 455 g = (v >> 3) & 0xfc; 456 b = (v << 3) & 0xf8; 457 ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); 458 s += 2; 459 d += BPP; 460 } while (--w != 0); 461 #endif 462 } 463 464 /* 465 * 24 bit color 466 */ 467 static void glue(vga_draw_line24_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d, 468 const uint8_t *s, int width) 469 { 470 int w; 471 uint32_t r, g, b; 472 473 w = width; 474 do { 475 #if defined(TARGET_WORDS_BIGENDIAN) 476 r = s[0]; 477 g = s[1]; 478 b = s[2]; 479 #else 480 b = s[0]; 481 g = s[1]; 482 r = s[2]; 483 #endif 484 ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); 485 s += 3; 486 d += BPP; 487 } while (--w != 0); 488 } 489 490 /* 491 * 32 bit color 492 */ 493 static void glue(vga_draw_line32_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d, 494 const uint8_t *s, int width) 495 { 496 #if DEPTH == 32 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT) 497 memcpy(d, s, width * 4); 498 #else 499 int w; 500 uint32_t r, g, b; 501 502 w = width; 503 do { 504 #if defined(TARGET_WORDS_BIGENDIAN) 505 r = s[1]; 506 g = s[2]; 507 b = s[3]; 508 #else 509 b = s[0]; 510 g = s[1]; 511 r = s[2]; 512 #endif 513 ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); 514 s += 4; 515 d += BPP; 516 } while (--w != 0); 517 #endif 518 } 519 520 #undef PUT_PIXEL2 521 #undef DEPTH 522 #undef BPP 523 #undef PIXEL_TYPE 524 #undef PIXEL_NAME 525 #undef BGR_FORMAT 526