1 /* Copyright (C) 2007-2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 #include "qemu_file.h" 13 #include "android/android.h" 14 #include "android/utils/debug.h" 15 #include "android/utils/duff.h" 16 #include "goldfish_device.h" 17 #include "console.h" 18 19 /* These values *must* match the platform definitions found under 20 * hardware/libhardware/include/hardware/hardware.h 21 */ 22 enum { 23 HAL_PIXEL_FORMAT_RGBA_8888 = 1, 24 HAL_PIXEL_FORMAT_RGBX_8888 = 2, 25 HAL_PIXEL_FORMAT_RGB_888 = 3, 26 HAL_PIXEL_FORMAT_RGB_565 = 4, 27 HAL_PIXEL_FORMAT_BGRA_8888 = 5, 28 HAL_PIXEL_FORMAT_RGBA_5551 = 6, 29 HAL_PIXEL_FORMAT_RGBA_4444 = 7, 30 }; 31 32 enum { 33 FB_GET_WIDTH = 0x00, 34 FB_GET_HEIGHT = 0x04, 35 FB_INT_STATUS = 0x08, 36 FB_INT_ENABLE = 0x0c, 37 FB_SET_BASE = 0x10, 38 FB_SET_ROTATION = 0x14, 39 FB_SET_BLANK = 0x18, 40 FB_GET_PHYS_WIDTH = 0x1c, 41 FB_GET_PHYS_HEIGHT = 0x20, 42 FB_GET_FORMAT = 0x24, 43 44 FB_INT_VSYNC = 1U << 0, 45 FB_INT_BASE_UPDATE_DONE = 1U << 1 46 }; 47 48 struct goldfish_fb_state { 49 struct goldfish_device dev; 50 DisplayState* ds; 51 int pixel_format; 52 int bytes_per_pixel; 53 uint32_t fb_base; 54 uint32_t base_valid : 1; 55 uint32_t need_update : 1; 56 uint32_t need_int : 1; 57 uint32_t set_rotation : 2; 58 uint32_t blank : 1; 59 uint32_t int_status; 60 uint32_t int_enable; 61 int rotation; /* 0, 1, 2 or 3 */ 62 int dpi; 63 }; 64 65 #define GOLDFISH_FB_SAVE_VERSION 2 66 67 static void goldfish_fb_save(QEMUFile* f, void* opaque) 68 { 69 struct goldfish_fb_state* s = opaque; 70 71 DisplayState* ds = s->ds; 72 73 qemu_put_be32(f, ds->surface->width); 74 qemu_put_be32(f, ds->surface->height); 75 qemu_put_be32(f, ds->surface->linesize); 76 qemu_put_byte(f, 0); 77 78 qemu_put_be32(f, s->fb_base); 79 qemu_put_byte(f, s->base_valid); 80 qemu_put_byte(f, s->need_update); 81 qemu_put_byte(f, s->need_int); 82 qemu_put_byte(f, s->set_rotation); 83 qemu_put_byte(f, s->blank); 84 qemu_put_be32(f, s->int_status); 85 qemu_put_be32(f, s->int_enable); 86 qemu_put_be32(f, s->rotation); 87 qemu_put_be32(f, s->dpi); 88 } 89 90 static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id) 91 { 92 struct goldfish_fb_state* s = opaque; 93 int ret = -1; 94 int ds_w, ds_h, ds_pitch, ds_rot; 95 96 if (version_id != GOLDFISH_FB_SAVE_VERSION) 97 goto Exit; 98 99 ds_w = qemu_get_be32(f); 100 ds_h = qemu_get_be32(f); 101 ds_pitch = qemu_get_be32(f); 102 ds_rot = qemu_get_byte(f); 103 104 DisplayState* ds = s->ds; 105 106 if (ds->surface->width != ds_w || 107 ds->surface->height != ds_h || 108 ds->surface->linesize != ds_pitch || 109 ds_rot != 0) 110 { 111 /* XXX: We should be able to force a resize/rotation from here ? */ 112 fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__); 113 goto Exit; 114 } 115 116 s->fb_base = qemu_get_be32(f); 117 s->base_valid = qemu_get_byte(f); 118 s->need_update = qemu_get_byte(f); 119 s->need_int = qemu_get_byte(f); 120 s->set_rotation = qemu_get_byte(f); 121 s->blank = qemu_get_byte(f); 122 s->int_status = qemu_get_be32(f); 123 s->int_enable = qemu_get_be32(f); 124 s->rotation = qemu_get_be32(f); 125 s->dpi = qemu_get_be32(f); 126 127 /* force a refresh */ 128 s->need_update = 1; 129 130 ret = 0; 131 Exit: 132 return ret; 133 } 134 135 /* Type used to record a mapping from display surface pixel format to 136 * HAL pixel format */ 137 typedef struct { 138 int pixel_format; /* HAL pixel format */ 139 uint8_t bits; 140 uint8_t bytes; 141 uint32_t rmask, gmask, bmask, amask; 142 } FbConfig; 143 144 145 /* Return the pixel format of the current framebuffer, based on 146 * the current display surface's pixel format. 147 * 148 * Note that you should not call this function from the device initialization 149 * function, because the display surface will change format before the kernel 150 * start. 151 */ 152 static int goldfish_fb_get_pixel_format(struct goldfish_fb_state *s) 153 { 154 if (s->pixel_format >= 0) { 155 return s->pixel_format; 156 } 157 static const FbConfig fb_configs[] = { 158 { HAL_PIXEL_FORMAT_RGB_565, 16, 2, 0xf800, 0x7e0, 0x1f, 0x0 }, 159 { HAL_PIXEL_FORMAT_RGBX_8888, 32, 4, 0xff0000, 0xff00, 0xff, 0x0 }, 160 { HAL_PIXEL_FORMAT_RGBA_8888, 32, 4, 0xff0000, 0xff00, 0xff, 0xff000000 }, 161 { -1, } 162 }; 163 164 /* Determine HAL pixel format value based on s->ds */ 165 struct PixelFormat* pf = &s->ds->surface->pf; 166 if (VERBOSE_CHECK(init)) { 167 printf("%s:%d: display surface,pixel format:\n", __FUNCTION__, __LINE__); 168 printf(" bits/pixel: %d\n", pf->bits_per_pixel); 169 printf(" bytes/pixel: %d\n", pf->bytes_per_pixel); 170 printf(" depth: %d\n", pf->depth); 171 printf(" red: bits=%d mask=0x%x shift=%d max=0x%x\n", 172 pf->rbits, pf->rmask, pf->rshift, pf->rmax); 173 printf(" green: bits=%d mask=0x%x shift=%d max=0x%x\n", 174 pf->gbits, pf->gmask, pf->gshift, pf->gmax); 175 printf(" blue: bits=%d mask=0x%x shift=%d max=0x%x\n", 176 pf->bbits, pf->bmask, pf->bshift, pf->bmax); 177 printf(" alpha: bits=%d mask=0x%x shift=%d max=0x%x\n", 178 pf->abits, pf->amask, pf->ashift, pf->amax); 179 } 180 181 s->bytes_per_pixel = pf->bytes_per_pixel; 182 int nn; 183 for (nn = 0; fb_configs[nn].pixel_format >= 0; nn++) { 184 const FbConfig* fbc = &fb_configs[nn]; 185 if (pf->bits_per_pixel == fbc->bits && 186 pf->bytes_per_pixel == fbc->bytes && 187 pf->rmask == fbc->rmask && 188 pf->gmask == fbc->gmask && 189 pf->bmask == fbc->bmask && 190 pf->amask == fbc->amask) { 191 /* We found it */ 192 s->pixel_format = fbc->pixel_format; 193 return s->pixel_format; 194 } 195 } 196 fprintf(stderr, "%s:%d: Unsupported display pixel format (depth=%d, bytespp=%d, bitspp=%d)\n", 197 __FUNCTION__, __LINE__, 198 pf->depth, 199 pf->bytes_per_pixel, 200 pf->bits_per_pixel); 201 exit(1); 202 return -1; 203 } 204 205 static int goldfish_fb_get_bytes_per_pixel(struct goldfish_fb_state *s) 206 { 207 if (s->pixel_format < 0) { 208 (void) goldfish_fb_get_pixel_format(s); 209 } 210 return s->bytes_per_pixel; 211 } 212 213 static int 214 pixels_to_mm(int pixels, int dpi) 215 { 216 /* dpi = dots / inch 217 ** inch = dots / dpi 218 ** mm / 25.4 = dots / dpi 219 ** mm = (dots * 25.4)/dpi 220 */ 221 return (int)(0.5 + 25.4 * pixels / dpi); 222 } 223 224 225 #define STATS 0 226 227 #if STATS 228 static int stats_counter; 229 static long stats_total; 230 static int stats_full_updates; 231 static long stats_total_full_updates; 232 #endif 233 234 /* This structure is used to hold the inputs for 235 * compute_fb_update_rect_linear below. 236 * This corresponds to the source framebuffer and destination 237 * surface pixel buffers. 238 */ 239 typedef struct { 240 int width; 241 int height; 242 int bytes_per_pixel; 243 const uint8_t* src_pixels; 244 int src_pitch; 245 uint8_t* dst_pixels; 246 int dst_pitch; 247 } FbUpdateState; 248 249 /* This structure is used to hold the outputs for 250 * compute_fb_update_rect_linear below. 251 * This corresponds to the smalled bounding rectangle of the 252 * latest framebuffer update. 253 */ 254 typedef struct { 255 int xmin, ymin, xmax, ymax; 256 } FbUpdateRect; 257 258 /* Determine the smallest bounding rectangle of pixels which changed 259 * between the source (framebuffer) and destination (surface) pixel 260 * buffers. 261 * 262 * Return 0 if there was no change, otherwise, populate '*rect' 263 * and return 1. 264 * 265 * If 'dirty_base' is not 0, it is a physical address that will be 266 * used to speed-up the check using the VGA dirty bits. In practice 267 * this is only used if your kernel driver does not implement. 268 * 269 * This function assumes that the framebuffers are in linear memory. 270 * This may change later when we want to support larger framebuffers 271 * that exceed the max DMA aperture size though. 272 */ 273 static int 274 compute_fb_update_rect_linear(FbUpdateState* fbs, 275 uint32_t dirty_base, 276 FbUpdateRect* rect) 277 { 278 int yy; 279 int width = fbs->width; 280 const uint8_t* src_line = fbs->src_pixels; 281 uint8_t* dst_line = fbs->dst_pixels; 282 uint32_t dirty_addr = dirty_base; 283 rect->xmin = rect->ymin = INT_MAX; 284 rect->xmax = rect->ymax = INT_MIN; 285 for (yy = 0; yy < fbs->height; yy++) { 286 int xx1, xx2; 287 /* If dirty_addr is != 0, then use it as a physical address to 288 * use the VGA dirty bits table to speed up the detection of 289 * changed pixels. 290 */ 291 if (dirty_addr != 0) { 292 int dirty = 0; 293 int len = fbs->src_pitch; 294 295 while (len > 0) { 296 int len2 = TARGET_PAGE_SIZE - (dirty_addr & (TARGET_PAGE_SIZE-1)); 297 298 if (len2 > len) 299 len2 = len; 300 301 dirty |= cpu_physical_memory_get_dirty(dirty_addr, VGA_DIRTY_FLAG); 302 dirty_addr += len2; 303 len -= len2; 304 } 305 306 if (!dirty) { /* this line was not modified, skip to next one */ 307 goto NEXT_LINE; 308 } 309 } 310 311 /* Then compute actual bounds of the changed pixels, while 312 * copying them from 'src' to 'dst'. This depends on the pixel depth. 313 */ 314 switch (fbs->bytes_per_pixel) { 315 case 2: 316 { 317 const uint16_t* src = (const uint16_t*) src_line; 318 uint16_t* dst = (uint16_t*) dst_line; 319 320 xx1 = 0; 321 DUFF4(width, { 322 uint16_t spix = src[xx1]; 323 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) 324 spix = (uint16_t)((spix << 8) | (spix >> 8)); 325 #endif 326 if (spix != dst[xx1]) 327 break; 328 xx1++; 329 }); 330 if (xx1 == width) { 331 break; 332 } 333 xx2 = width-1; 334 DUFF4(xx2-xx1, { 335 if (src[xx2] != dst[xx2]) 336 break; 337 xx2--; 338 }); 339 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) 340 /* Convert the guest pixels into host ones */ 341 int xx = xx1; 342 DUFF4(xx2-xx1+1,{ 343 unsigned spix = src[xx]; 344 dst[xx] = (uint16_t)((spix << 8) | (spix >> 8)); 345 xx++; 346 }); 347 #else 348 memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*2 ); 349 #endif 350 break; 351 } 352 353 case 3: 354 { 355 xx1 = 0; 356 DUFF4(width, { 357 int xx = xx1*3; 358 if (src_line[xx+0] != dst_line[xx+0] || 359 src_line[xx+1] != dst_line[xx+1] || 360 src_line[xx+2] != dst_line[xx+2]) { 361 break; 362 } 363 xx1 ++; 364 }); 365 if (xx1 == width) { 366 break; 367 } 368 xx2 = width-1; 369 DUFF4(xx2-xx1,{ 370 int xx = xx2*3; 371 if (src_line[xx+0] != dst_line[xx+0] || 372 src_line[xx+1] != dst_line[xx+1] || 373 src_line[xx+2] != dst_line[xx+2]) { 374 break; 375 } 376 xx2--; 377 }); 378 memcpy( dst_line+xx1*3, src_line+xx1*3, (xx2-xx1+1)*3 ); 379 break; 380 } 381 382 case 4: 383 { 384 const uint32_t* src = (const uint32_t*) src_line; 385 uint32_t* dst = (uint32_t*) dst_line; 386 387 xx1 = 0; 388 DUFF4(width, { 389 uint32_t spix = src[xx1]; 390 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) 391 spix = (spix << 16) | (spix >> 16); 392 spix = ((spix << 8) & 0xff00ff00) | ((spix >> 8) & 0x00ff00ff); 393 #endif 394 if (spix != dst[xx1]) { 395 break; 396 } 397 xx1++; 398 }); 399 if (xx1 == width) { 400 break; 401 } 402 xx2 = width-1; 403 DUFF4(xx2-xx1,{ 404 if (src[xx2] != dst[xx2]) { 405 break; 406 } 407 xx2--; 408 }); 409 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) 410 /* Convert the guest pixels into host ones */ 411 int xx = xx1; 412 DUFF4(xx2-xx1+1,{ 413 uint32_t spix = src[xx]; 414 spix = (spix << 16) | (spix >> 16); 415 spix = ((spix << 8) & 0xff00ff00) | ((spix >> 8) & 0x00ff00ff); 416 dst[xx] = spix; 417 xx++; 418 }) 419 #else 420 memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*4 ); 421 #endif 422 break; 423 } 424 default: 425 return 0; 426 } 427 /* Update bounds if pixels on this line were modified */ 428 if (xx1 < width) { 429 if (xx1 < rect->xmin) rect->xmin = xx1; 430 if (xx2 > rect->xmax) rect->xmax = xx2; 431 if (yy < rect->ymin) rect->ymin = yy; 432 if (yy > rect->ymax) rect->ymax = yy; 433 } 434 NEXT_LINE: 435 src_line += fbs->src_pitch; 436 dst_line += fbs->dst_pitch; 437 } 438 439 if (rect->ymin > rect->ymax) { /* nothing changed */ 440 return 0; 441 } 442 443 /* Always clear the dirty VGA bits */ 444 cpu_physical_memory_reset_dirty(dirty_base + rect->ymin * fbs->src_pitch, 445 dirty_base + (rect->ymax+1)* fbs->src_pitch, 446 VGA_DIRTY_FLAG); 447 return 1; 448 } 449 450 451 static void goldfish_fb_update_display(void *opaque) 452 { 453 struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; 454 uint32_t base; 455 uint8_t* dst_line; 456 uint8_t* src_line; 457 int full_update = 0; 458 int width, height, pitch; 459 460 base = s->fb_base; 461 if(base == 0) 462 return; 463 464 if((s->int_enable & FB_INT_VSYNC) && !(s->int_status & FB_INT_VSYNC)) { 465 s->int_status |= FB_INT_VSYNC; 466 goldfish_device_set_irq(&s->dev, 0, 1); 467 } 468 469 if(s->need_update) { 470 full_update = 1; 471 if(s->need_int) { 472 s->int_status |= FB_INT_BASE_UPDATE_DONE; 473 if(s->int_enable & FB_INT_BASE_UPDATE_DONE) 474 goldfish_device_set_irq(&s->dev, 0, 1); 475 } 476 s->need_int = 0; 477 s->need_update = 0; 478 } 479 480 src_line = qemu_get_ram_ptr( base ); 481 482 dst_line = s->ds->surface->data; 483 pitch = s->ds->surface->linesize; 484 width = s->ds->surface->width; 485 height = s->ds->surface->height; 486 487 FbUpdateState fbs; 488 FbUpdateRect rect; 489 490 fbs.width = width; 491 fbs.height = height; 492 fbs.dst_pixels = dst_line; 493 fbs.dst_pitch = pitch; 494 fbs.bytes_per_pixel = goldfish_fb_get_bytes_per_pixel(s); 495 496 fbs.src_pixels = src_line; 497 fbs.src_pitch = width*s->ds->surface->pf.bytes_per_pixel; 498 499 500 #if STATS 501 if (full_update) 502 stats_full_updates += 1; 503 if (++stats_counter == 120) { 504 stats_total += stats_counter; 505 stats_total_full_updates += stats_full_updates; 506 507 printf( "full update stats: peak %.2f %% total %.2f %%\n", 508 stats_full_updates*100.0/stats_counter, 509 stats_total_full_updates*100.0/stats_total ); 510 511 stats_counter = 0; 512 stats_full_updates = 0; 513 } 514 #endif /* STATS */ 515 516 if (s->blank) 517 { 518 memset( dst_line, 0, height*pitch ); 519 rect.xmin = 0; 520 rect.ymin = 0; 521 rect.xmax = width-1; 522 rect.ymax = height-1; 523 } 524 else 525 { 526 if (full_update) { /* don't use dirty-bits optimization */ 527 base = 0; 528 } 529 if (compute_fb_update_rect_linear(&fbs, base, &rect) == 0) { 530 return; 531 } 532 } 533 534 rect.xmax += 1; 535 rect.ymax += 1; 536 #if 0 537 printf("goldfish_fb_update_display (y:%d,h:%d,x=%d,w=%d)\n", 538 rect.ymin, rect.ymax-rect.ymin, rect.xmin, rect.xmax-rect.xmin); 539 #endif 540 541 dpy_update(s->ds, rect.xmin, rect.ymin, rect.xmax-rect.xmin, rect.ymax-rect.ymin); 542 } 543 544 static void goldfish_fb_invalidate_display(void * opaque) 545 { 546 // is this called? 547 struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; 548 s->need_update = 1; 549 } 550 551 static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset) 552 { 553 uint32_t ret; 554 struct goldfish_fb_state *s = opaque; 555 556 switch(offset) { 557 case FB_GET_WIDTH: 558 ret = ds_get_width(s->ds); 559 //printf("FB_GET_WIDTH => %d\n", ret); 560 return ret; 561 562 case FB_GET_HEIGHT: 563 ret = ds_get_height(s->ds); 564 //printf( "FB_GET_HEIGHT = %d\n", ret); 565 return ret; 566 567 case FB_INT_STATUS: 568 ret = s->int_status & s->int_enable; 569 if(ret) { 570 s->int_status &= ~ret; 571 goldfish_device_set_irq(&s->dev, 0, 0); 572 } 573 return ret; 574 575 case FB_GET_PHYS_WIDTH: 576 ret = pixels_to_mm( ds_get_width(s->ds), s->dpi ); 577 //printf( "FB_GET_PHYS_WIDTH => %d\n", ret ); 578 return ret; 579 580 case FB_GET_PHYS_HEIGHT: 581 ret = pixels_to_mm( ds_get_height(s->ds), s->dpi ); 582 //printf( "FB_GET_PHYS_HEIGHT => %d\n", ret ); 583 return ret; 584 585 case FB_GET_FORMAT: 586 return goldfish_fb_get_pixel_format(s); 587 588 default: 589 cpu_abort (cpu_single_env, "goldfish_fb_read: Bad offset %x\n", offset); 590 return 0; 591 } 592 } 593 594 static void goldfish_fb_write(void *opaque, target_phys_addr_t offset, 595 uint32_t val) 596 { 597 struct goldfish_fb_state *s = opaque; 598 599 switch(offset) { 600 case FB_INT_ENABLE: 601 s->int_enable = val; 602 goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); 603 break; 604 case FB_SET_BASE: { 605 int need_resize = !s->base_valid; 606 s->fb_base = val; 607 s->int_status &= ~FB_INT_BASE_UPDATE_DONE; 608 s->need_update = 1; 609 s->need_int = 1; 610 s->base_valid = 1; 611 if(s->set_rotation != s->rotation) { 612 //printf("FB_SET_BASE: rotation : %d => %d\n", s->rotation, s->set_rotation); 613 s->rotation = s->set_rotation; 614 need_resize = 1; 615 } 616 goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); 617 if (need_resize) { 618 //printf("FB_SET_BASE: need resize (rotation=%d)\n", s->rotation ); 619 dpy_resize(s->ds); 620 } 621 } break; 622 case FB_SET_ROTATION: 623 //printf( "FB_SET_ROTATION %d\n", val); 624 s->set_rotation = val; 625 break; 626 case FB_SET_BLANK: 627 s->blank = val; 628 s->need_update = 1; 629 break; 630 default: 631 cpu_abort (cpu_single_env, "goldfish_fb_write: Bad offset %x\n", offset); 632 } 633 } 634 635 static CPUReadMemoryFunc *goldfish_fb_readfn[] = { 636 goldfish_fb_read, 637 goldfish_fb_read, 638 goldfish_fb_read 639 }; 640 641 static CPUWriteMemoryFunc *goldfish_fb_writefn[] = { 642 goldfish_fb_write, 643 goldfish_fb_write, 644 goldfish_fb_write 645 }; 646 647 void goldfish_fb_init(int id) 648 { 649 struct goldfish_fb_state *s; 650 651 s = (struct goldfish_fb_state *)qemu_mallocz(sizeof(*s)); 652 s->dev.name = "goldfish_fb"; 653 s->dev.id = id; 654 s->dev.size = 0x1000; 655 s->dev.irq_count = 1; 656 657 s->ds = graphic_console_init(goldfish_fb_update_display, 658 goldfish_fb_invalidate_display, 659 NULL, 660 NULL, 661 s); 662 663 s->dpi = 165; /* XXX: Find better way to get actual value ! */ 664 665 /* IMPORTANT: DO NOT COMPUTE s->pixel_format and s->bytes_per_pixel 666 * here because the display surface is going to change later. 667 */ 668 s->bytes_per_pixel = 0; 669 s->pixel_format = -1; 670 671 goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s); 672 673 register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION, 674 goldfish_fb_save, goldfish_fb_load, s); 675 } 676