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 static inline void vga_draw_glyph_line(uint8_t *d, uint32_t font_data, 26 uint32_t xorcol, uint32_t bgcol) 27 { 28 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; 29 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; 30 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; 31 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; 32 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; 33 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; 34 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; 35 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; 36 } 37 38 static void vga_draw_glyph8(uint8_t *d, int linesize, 39 const uint8_t *font_ptr, int h, 40 uint32_t fgcol, uint32_t bgcol) 41 { 42 uint32_t font_data, xorcol; 43 44 xorcol = bgcol ^ fgcol; 45 do { 46 font_data = font_ptr[0]; 47 vga_draw_glyph_line(d, font_data, xorcol, bgcol); 48 font_ptr += 4; 49 d += linesize; 50 } while (--h); 51 } 52 53 static void vga_draw_glyph16(uint8_t *d, int linesize, 54 const uint8_t *font_ptr, int h, 55 uint32_t fgcol, uint32_t bgcol) 56 { 57 uint32_t font_data, xorcol; 58 59 xorcol = bgcol ^ fgcol; 60 do { 61 font_data = font_ptr[0]; 62 vga_draw_glyph_line(d, expand4to8[font_data >> 4], 63 xorcol, bgcol); 64 vga_draw_glyph_line(d + 32, expand4to8[font_data & 0x0f], 65 xorcol, bgcol); 66 font_ptr += 4; 67 d += linesize; 68 } while (--h); 69 } 70 71 static void vga_draw_glyph9(uint8_t *d, int linesize, 72 const uint8_t *font_ptr, int h, 73 uint32_t fgcol, uint32_t bgcol, int dup9) 74 { 75 uint32_t font_data, xorcol, v; 76 77 xorcol = bgcol ^ fgcol; 78 do { 79 font_data = font_ptr[0]; 80 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; 81 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; 82 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; 83 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; 84 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; 85 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; 86 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; 87 v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; 88 ((uint32_t *)d)[7] = v; 89 if (dup9) 90 ((uint32_t *)d)[8] = v; 91 else 92 ((uint32_t *)d)[8] = bgcol; 93 font_ptr += 4; 94 d += linesize; 95 } while (--h); 96 } 97 98 /* 99 * 4 color mode 100 */ 101 static void *vga_draw_line2(VGACommonState *vga, uint8_t *d, 102 uint32_t addr, int width, int hpel) 103 { 104 uint32_t plane_mask, *palette, data, v; 105 int x; 106 107 palette = vga->last_palette; 108 plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; 109 hpel &= 7; 110 if (hpel) { 111 width += 8; 112 d = vga->panning_buf; 113 } 114 width >>= 3; 115 for(x = 0; x < width; x++) { 116 data = vga_read_dword_le(vga, addr & (VGA_VRAM_SIZE - 1)); 117 data &= plane_mask; 118 v = expand2[GET_PLANE(data, 0)]; 119 v |= expand2[GET_PLANE(data, 2)] << 2; 120 ((uint32_t *)d)[0] = palette[v >> 12]; 121 ((uint32_t *)d)[1] = palette[(v >> 8) & 0xf]; 122 ((uint32_t *)d)[2] = palette[(v >> 4) & 0xf]; 123 ((uint32_t *)d)[3] = palette[(v >> 0) & 0xf]; 124 125 v = expand2[GET_PLANE(data, 1)]; 126 v |= expand2[GET_PLANE(data, 3)] << 2; 127 ((uint32_t *)d)[4] = palette[v >> 12]; 128 ((uint32_t *)d)[5] = palette[(v >> 8) & 0xf]; 129 ((uint32_t *)d)[6] = palette[(v >> 4) & 0xf]; 130 ((uint32_t *)d)[7] = palette[(v >> 0) & 0xf]; 131 d += 32; 132 addr += 4; 133 } 134 return hpel ? vga->panning_buf + 4 * hpel : NULL; 135 } 136 137 #define PUT_PIXEL2(d, n, v) \ 138 ((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v) 139 140 /* 141 * 4 color mode, dup2 horizontal 142 */ 143 static void *vga_draw_line2d2(VGACommonState *vga, uint8_t *d, 144 uint32_t addr, int width, int hpel) 145 { 146 uint32_t plane_mask, *palette, data, v; 147 int x; 148 149 palette = vga->last_palette; 150 plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; 151 hpel &= 7; 152 if (hpel) { 153 width += 8; 154 d = vga->panning_buf; 155 } 156 width >>= 3; 157 for(x = 0; x < width; x++) { 158 data = vga_read_dword_le(vga, addr & (VGA_VRAM_SIZE - 1)); 159 data &= plane_mask; 160 v = expand2[GET_PLANE(data, 0)]; 161 v |= expand2[GET_PLANE(data, 2)] << 2; 162 PUT_PIXEL2(d, 0, palette[v >> 12]); 163 PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]); 164 PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]); 165 PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]); 166 167 v = expand2[GET_PLANE(data, 1)]; 168 v |= expand2[GET_PLANE(data, 3)] << 2; 169 PUT_PIXEL2(d, 4, palette[v >> 12]); 170 PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); 171 PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); 172 PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); 173 d += 64; 174 addr += 4; 175 } 176 return hpel ? vga->panning_buf + 8 * hpel : NULL; 177 } 178 179 /* 180 * 16 color mode 181 */ 182 static void *vga_draw_line4(VGACommonState *vga, uint8_t *d, 183 uint32_t addr, int width, int hpel) 184 { 185 uint32_t plane_mask, data, v, *palette; 186 int x; 187 188 palette = vga->last_palette; 189 plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; 190 hpel &= 7; 191 if (hpel) { 192 width += 8; 193 d = vga->panning_buf; 194 } 195 width >>= 3; 196 for(x = 0; x < width; x++) { 197 data = vga_read_dword_le(vga, addr & (VGA_VRAM_SIZE - 1)); 198 data &= plane_mask; 199 v = expand4[GET_PLANE(data, 0)]; 200 v |= expand4[GET_PLANE(data, 1)] << 1; 201 v |= expand4[GET_PLANE(data, 2)] << 2; 202 v |= expand4[GET_PLANE(data, 3)] << 3; 203 ((uint32_t *)d)[0] = palette[v >> 28]; 204 ((uint32_t *)d)[1] = palette[(v >> 24) & 0xf]; 205 ((uint32_t *)d)[2] = palette[(v >> 20) & 0xf]; 206 ((uint32_t *)d)[3] = palette[(v >> 16) & 0xf]; 207 ((uint32_t *)d)[4] = palette[(v >> 12) & 0xf]; 208 ((uint32_t *)d)[5] = palette[(v >> 8) & 0xf]; 209 ((uint32_t *)d)[6] = palette[(v >> 4) & 0xf]; 210 ((uint32_t *)d)[7] = palette[(v >> 0) & 0xf]; 211 d += 32; 212 addr += 4; 213 } 214 return hpel ? vga->panning_buf + 4 * hpel : NULL; 215 } 216 217 /* 218 * 16 color mode, dup2 horizontal 219 */ 220 static void *vga_draw_line4d2(VGACommonState *vga, uint8_t *d, 221 uint32_t addr, int width, int hpel) 222 { 223 uint32_t plane_mask, data, v, *palette; 224 int x; 225 226 palette = vga->last_palette; 227 plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; 228 hpel &= 7; 229 if (hpel) { 230 width += 8; 231 d = vga->panning_buf; 232 } 233 width >>= 3; 234 for(x = 0; x < width; x++) { 235 data = vga_read_dword_le(vga, addr & (VGA_VRAM_SIZE - 1)); 236 data &= plane_mask; 237 v = expand4[GET_PLANE(data, 0)]; 238 v |= expand4[GET_PLANE(data, 1)] << 1; 239 v |= expand4[GET_PLANE(data, 2)] << 2; 240 v |= expand4[GET_PLANE(data, 3)] << 3; 241 PUT_PIXEL2(d, 0, palette[v >> 28]); 242 PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]); 243 PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]); 244 PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]); 245 PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]); 246 PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); 247 PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); 248 PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); 249 d += 64; 250 addr += 4; 251 } 252 return hpel ? vga->panning_buf + 8 * hpel : NULL; 253 } 254 255 /* 256 * 256 color mode, double pixels 257 * 258 * XXX: add plane_mask support (never used in standard VGA modes) 259 */ 260 static void *vga_draw_line8d2(VGACommonState *vga, uint8_t *d, 261 uint32_t addr, int width, int hpel) 262 { 263 uint32_t *palette; 264 int x; 265 266 palette = vga->last_palette; 267 hpel = (hpel >> 1) & 3; 268 269 /* For 256 color modes, we can adjust the source address and write directly 270 * to the destination, even if horizontal pel panning is active. However, 271 * the loop below assumes that the address does not wrap in the middle of a 272 * plane. If that happens... 273 */ 274 if (addr + (width >> 3) * 4 < VGA_VRAM_SIZE) { 275 addr += hpel * 4; 276 hpel = 0; 277 } 278 279 /* ... use the panning buffer as in planar modes. */ 280 if (hpel) { 281 width += 8; 282 d = vga->panning_buf; 283 } 284 width >>= 3; 285 for(x = 0; x < width; x++) { 286 addr &= VGA_VRAM_SIZE - 1; 287 PUT_PIXEL2(d, 0, palette[vga_read_byte(vga, addr + 0)]); 288 PUT_PIXEL2(d, 1, palette[vga_read_byte(vga, addr + 1)]); 289 PUT_PIXEL2(d, 2, palette[vga_read_byte(vga, addr + 2)]); 290 PUT_PIXEL2(d, 3, palette[vga_read_byte(vga, addr + 3)]); 291 d += 32; 292 addr += 4; 293 } 294 return hpel ? vga->panning_buf + 8 * hpel : NULL; 295 } 296 297 /* 298 * standard 256 color mode 299 * 300 * XXX: add plane_mask support (never used in standard VGA modes) 301 */ 302 static void *vga_draw_line8(VGACommonState *vga, uint8_t *d, 303 uint32_t addr, int width, int hpel) 304 { 305 uint32_t *palette; 306 int x; 307 308 palette = vga->last_palette; 309 hpel = (hpel >> 1) & 3; 310 if (hpel) { 311 width += 8; 312 d = vga->panning_buf; 313 } 314 width >>= 3; 315 for(x = 0; x < width; x++) { 316 ((uint32_t *)d)[0] = palette[vga_read_byte(vga, addr + 0)]; 317 ((uint32_t *)d)[1] = palette[vga_read_byte(vga, addr + 1)]; 318 ((uint32_t *)d)[2] = palette[vga_read_byte(vga, addr + 2)]; 319 ((uint32_t *)d)[3] = palette[vga_read_byte(vga, addr + 3)]; 320 ((uint32_t *)d)[4] = palette[vga_read_byte(vga, addr + 4)]; 321 ((uint32_t *)d)[5] = palette[vga_read_byte(vga, addr + 5)]; 322 ((uint32_t *)d)[6] = palette[vga_read_byte(vga, addr + 6)]; 323 ((uint32_t *)d)[7] = palette[vga_read_byte(vga, addr + 7)]; 324 d += 32; 325 addr += 8; 326 } 327 return hpel ? vga->panning_buf + 4 * hpel : NULL; 328 } 329 330 /* 331 * 15 bit color 332 */ 333 static void *vga_draw_line15_le(VGACommonState *vga, uint8_t *d, 334 uint32_t addr, int width, int hpel) 335 { 336 int w; 337 uint32_t v, r, g, b; 338 339 w = width; 340 do { 341 v = vga_read_word_le(vga, addr); 342 r = (v >> 7) & 0xf8; 343 g = (v >> 2) & 0xf8; 344 b = (v << 3) & 0xf8; 345 ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); 346 addr += 2; 347 d += 4; 348 } while (--w != 0); 349 return NULL; 350 } 351 352 static void *vga_draw_line15_be(VGACommonState *vga, uint8_t *d, 353 uint32_t addr, int width, int hpel) 354 { 355 int w; 356 uint32_t v, r, g, b; 357 358 w = width; 359 do { 360 v = vga_read_word_be(vga, addr); 361 r = (v >> 7) & 0xf8; 362 g = (v >> 2) & 0xf8; 363 b = (v << 3) & 0xf8; 364 ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); 365 addr += 2; 366 d += 4; 367 } while (--w != 0); 368 return NULL; 369 } 370 371 /* 372 * 16 bit color 373 */ 374 static void *vga_draw_line16_le(VGACommonState *vga, uint8_t *d, 375 uint32_t addr, int width, int hpel) 376 { 377 int w; 378 uint32_t v, r, g, b; 379 380 w = width; 381 do { 382 v = vga_read_word_le(vga, addr); 383 r = (v >> 8) & 0xf8; 384 g = (v >> 3) & 0xfc; 385 b = (v << 3) & 0xf8; 386 ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); 387 addr += 2; 388 d += 4; 389 } while (--w != 0); 390 return NULL; 391 } 392 393 static void *vga_draw_line16_be(VGACommonState *vga, uint8_t *d, 394 uint32_t addr, int width, int hpel) 395 { 396 int w; 397 uint32_t v, r, g, b; 398 399 w = width; 400 do { 401 v = vga_read_word_be(vga, addr); 402 r = (v >> 8) & 0xf8; 403 g = (v >> 3) & 0xfc; 404 b = (v << 3) & 0xf8; 405 ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); 406 addr += 2; 407 d += 4; 408 } while (--w != 0); 409 return NULL; 410 } 411 412 /* 413 * 24 bit color 414 */ 415 static void *vga_draw_line24_le(VGACommonState *vga, uint8_t *d, 416 uint32_t addr, int width, int hpel) 417 { 418 int w; 419 uint32_t r, g, b; 420 421 w = width; 422 do { 423 b = vga_read_byte(vga, addr + 0); 424 g = vga_read_byte(vga, addr + 1); 425 r = vga_read_byte(vga, addr + 2); 426 ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); 427 addr += 3; 428 d += 4; 429 } while (--w != 0); 430 return NULL; 431 } 432 433 static void *vga_draw_line24_be(VGACommonState *vga, uint8_t *d, 434 uint32_t addr, int width, int hpel) 435 { 436 int w; 437 uint32_t r, g, b; 438 439 w = width; 440 do { 441 r = vga_read_byte(vga, addr + 0); 442 g = vga_read_byte(vga, addr + 1); 443 b = vga_read_byte(vga, addr + 2); 444 ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); 445 addr += 3; 446 d += 4; 447 } while (--w != 0); 448 return NULL; 449 } 450 451 /* 452 * 32 bit color 453 */ 454 static void *vga_draw_line32_le(VGACommonState *vga, uint8_t *d, 455 uint32_t addr, int width, int hpel) 456 { 457 int w; 458 uint32_t r, g, b; 459 460 w = width; 461 do { 462 b = vga_read_byte(vga, addr + 0); 463 g = vga_read_byte(vga, addr + 1); 464 r = vga_read_byte(vga, addr + 2); 465 ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); 466 addr += 4; 467 d += 4; 468 } while (--w != 0); 469 return NULL; 470 } 471 472 static void *vga_draw_line32_be(VGACommonState *vga, uint8_t *d, 473 uint32_t addr, int width, int hpel) 474 { 475 int w; 476 uint32_t r, g, b; 477 478 w = width; 479 do { 480 r = vga_read_byte(vga, addr + 1); 481 g = vga_read_byte(vga, addr + 2); 482 b = vga_read_byte(vga, addr + 3); 483 ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); 484 addr += 4; 485 d += 4; 486 } while (--w != 0); 487 return NULL; 488 } 489