From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:49720) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QvQyY-0003tm-TZ for qemu-devel@nongnu.org; Mon, 22 Aug 2011 05:39:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QvQyU-00079F-Qw for qemu-devel@nongnu.org; Mon, 22 Aug 2011 05:39:22 -0400 Received: from mail-qy0-f180.google.com ([209.85.216.180]:37851) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QvQyU-00078w-AF for qemu-devel@nongnu.org; Mon, 22 Aug 2011 05:39:18 -0400 Received: by qyk31 with SMTP id 31so2312351qyk.4 for ; Mon, 22 Aug 2011 02:39:12 -0700 (PDT) MIME-Version: 1.0 Date: Mon, 22 Aug 2011 05:39:12 -0400 Message-ID: From: Patrick Jackson Content-Type: multipart/alternative; boundary=00248c7119dd0ae82104ab14da30 Subject: [Qemu-devel] [PATCH 07/11] Goldfish: Added the framebuffer device. List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --00248c7119dd0ae82104ab14da30 Content-Type: text/plain; charset=ISO-8859-1 Handles the framebuffer for the Android kernel. Also manages pixel conversions as the Android kernel only works with the RGB_565 format. Signed-off-by: Patrick Jackson --- Makefile.target | 2 +- hw/android_arm.c | 1 + hw/goldfish_device.h | 1 + hw/goldfish_fb.c | 740 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 743 insertions(+), 1 deletions(-) create mode 100644 hw/goldfish_fb.c diff --git a/Makefile.target b/Makefile.target index ea9a741..020aba6 100644 --- a/Makefile.target +++ b/Makefile.target @@ -361,7 +361,7 @@ obj-arm-y += vexpress.o obj-arm-y += strongarm.o obj-arm-y += collie.o obj-arm-y += android_arm.o goldfish_device.o goldfish_interrupt.o goldfish_timer.o -obj-arm-y += goldfish_tty.o goldfish_nand.o +obj-arm-y += goldfish_tty.o goldfish_nand.o goldfish_fb.o obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o diff --git a/hw/android_arm.c b/hw/android_arm.c index bf49b74..38fd3d2 100644 --- a/hw/android_arm.c +++ b/hw/android_arm.c @@ -65,6 +65,7 @@ static void android_arm_init_(ram_addr_t ram_size, } } + goldfish_fb_create(gbus, 0); goldfish_nand_create(gbus); info.ram_size = ram_size; diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h index 91d74fd..1ec5646 100644 --- a/hw/goldfish_device.h +++ b/hw/goldfish_device.h @@ -47,6 +47,7 @@ DeviceState *goldfish_timer_create(GoldfishBus *gbus, uint32_t base, int irq); DeviceState *goldfish_rtc_create(GoldfishBus *gbus); DeviceState *goldfish_tty_create(GoldfishBus *gbus, CharDriverState *cs, int id, uint32_t base, int irq); DeviceState *goldfish_nand_create(GoldfishBus *gbus); +DeviceState *goldfish_fb_create(GoldfishBus *gbus, int id); /* Global functions provided by Goldfish devices */ void goldfish_bus_register_withprop(GoldfishDeviceInfo *info); diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c new file mode 100644 index 0000000..1b45ba4 --- /dev/null +++ b/hw/goldfish_fb.c @@ -0,0 +1,740 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "goldfish_device.h" +#include "console.h" + +#define DUFF4(_count,_stmnt) \ + ({ \ + int __count = (_count); \ + int __n = (__count +3)/4; \ + switch (__count & 3) { \ + case 0: do { _stmnt; \ + case 3: _stmnt; \ + case 2: _stmnt; \ + case 1: _stmnt; \ + } while (--__n > 0); \ + } \ + }) + +/* These values *must* match the platform definitions found under + * hardware/libhardware/include/hardware/hardware.h + */ +enum { + HAL_PIXEL_FORMAT_RGBA_8888 = 1, + HAL_PIXEL_FORMAT_RGBX_8888 = 2, + HAL_PIXEL_FORMAT_RGB_888 = 3, + HAL_PIXEL_FORMAT_RGB_565 = 4, + HAL_PIXEL_FORMAT_BGRA_8888 = 5, + HAL_PIXEL_FORMAT_RGBA_5551 = 6, + HAL_PIXEL_FORMAT_RGBA_4444 = 7, +}; + +enum { + FB_GET_WIDTH = 0x00, + FB_GET_HEIGHT = 0x04, + FB_INT_STATUS = 0x08, + FB_INT_ENABLE = 0x0c, + FB_SET_BASE = 0x10, + FB_SET_ROTATION = 0x14, + FB_SET_BLANK = 0x18, + FB_GET_PHYS_WIDTH = 0x1c, + FB_GET_PHYS_HEIGHT = 0x20, + FB_GET_FORMAT = 0x24, + + FB_INT_VSYNC = 1U << 0, + FB_INT_BASE_UPDATE_DONE = 1U << 1 +}; + +typedef struct GoldfishFBDevice { + GoldfishDevice dev; + DisplayState* ds; + int pixel_format; + int bytes_per_pixel; + uint32_t fb_base; + uint32_t base_valid : 1; + uint32_t need_update : 1; + uint32_t need_int : 1; + uint32_t set_rotation : 2; + uint32_t blank : 1; + uint32_t int_status; + uint32_t int_enable; + int rotation; /* 0, 1, 2 or 3 */ + int dpi; +} GoldfishFBDevice; + +/* Type used to record a mapping from display surface pixel format to + * HAL pixel format */ +typedef struct { + int pixel_format; /* HAL pixel format */ + uint8_t bits; + uint8_t bytes; + uint32_t rmask, gmask, bmask, amask; +} FbConfig; + + +/* Return the pixel format of the current framebuffer, based on + * the current display surface's pixel format. + * + * Note that you should not call this function from the device initialization + * function, because the display surface will change format before the kernel + * start. + */ +static int goldfish_fb_get_pixel_format(GoldfishFBDevice *s) +{ + if (s->pixel_format >= 0) { + return s->pixel_format; + } + static const FbConfig fb_configs[] = { + { HAL_PIXEL_FORMAT_RGB_565, 16, 2, 0xf800, 0x7e0, 0x1f, 0x0 }, + { HAL_PIXEL_FORMAT_RGBX_8888, 32, 4, 0xff0000, 0xff00, 0xff, 0x0 }, + { HAL_PIXEL_FORMAT_RGBA_8888, 32, 4, 0xff0000, 0xff00, 0xff, 0xff000000 }, + { -1, } + }; + + /* Determine HAL pixel format value based on s->ds */ + struct PixelFormat* pf = &s->ds->surface->pf; +#if 0 + printf("%s:%d: display surface,pixel format:\n", __FUNCTION__, __LINE__); + printf(" bits/pixel: %d\n", pf->bits_per_pixel); + printf(" bytes/pixel: %d\n", pf->bytes_per_pixel); + printf(" depth: %d\n", pf->depth); + printf(" red: bits=%d mask=0x%x shift=%d max=0x%x\n", + pf->rbits, pf->rmask, pf->rshift, pf->rmax); + printf(" green: bits=%d mask=0x%x shift=%d max=0x%x\n", + pf->gbits, pf->gmask, pf->gshift, pf->gmax); + printf(" blue: bits=%d mask=0x%x shift=%d max=0x%x\n", + pf->bbits, pf->bmask, pf->bshift, pf->bmax); + printf(" alpha: bits=%d mask=0x%x shift=%d max=0x%x\n", + pf->abits, pf->amask, pf->ashift, pf->amax); +#endif + + s->bytes_per_pixel = pf->bytes_per_pixel; + int nn; + for (nn = 0; fb_configs[nn].pixel_format >= 0; nn++) { + const FbConfig* fbc = &fb_configs[nn]; + if (pf->bits_per_pixel == fbc->bits && + pf->bytes_per_pixel == fbc->bytes && + pf->rmask == fbc->rmask && + pf->gmask == fbc->gmask && + pf->bmask == fbc->bmask && + pf->amask == fbc->amask) { + /* We found it */ + s->pixel_format = fbc->pixel_format; + return s->pixel_format; + } + } + fprintf(stderr, "%s:%d: Unsupported display pixel format (depth=%d, bytespp=%d, bitspp=%d)\n", + __FUNCTION__, __LINE__, + pf->depth, + pf->bytes_per_pixel, + pf->bits_per_pixel); + exit(1); + return -1; +} + +static int goldfish_fb_get_bytes_per_pixel(GoldfishFBDevice *s) +{ + if (s->pixel_format < 0) { + (void) goldfish_fb_get_pixel_format(s); + } + return s->bytes_per_pixel; +} + +static int +pixels_to_mm(int pixels, int dpi) +{ + /* dpi = dots / inch + ** inch = dots / dpi + ** mm / 25.4 = dots / dpi + ** mm = (dots * 25.4)/dpi + */ + return (int)(0.5 + 25.4 * pixels / dpi); +} + +static uint32_t convert_pix(uint32_t rgb, struct PixelFormat* pf_out, struct PixelFormat* pf_in) +{ + // Pixel conversion + uint8_t red = (rgb & pf_in->rmask) >> pf_in->rshift; + uint8_t green = (rgb & pf_in->gmask) >> pf_in->gshift; + uint8_t blue = (rgb & pf_in->bmask) >> pf_in->bshift; + red <<= pf_out->rbits - pf_in->rbits; + green <<= pf_out->gbits - pf_in->gbits; + blue <<= pf_out->bbits - pf_in->bbits; + return (blue << pf_out->bshift) | (green << pf_out->gshift) | (red << pf_out->rshift); +} + + +#define STATS 0 + +#if STATS +static int stats_counter; +static long stats_total; +static int stats_full_updates; +static long stats_total_full_updates; +#endif + +/* This structure is used to hold the inputs for + * compute_fb_update_rect_linear below. + * This corresponds to the source framebuffer and destination + * surface pixel buffers. + */ +typedef struct { + int width; + int height; + int bytes_per_pixel; + const uint8_t* src_pixels; + int src_pitch; + PixelFormat* src_format; + uint8_t* dst_pixels; + int dst_pitch; + PixelFormat* dst_format; +} FbUpdateState; + +/* This structure is used to hold the outputs for + * compute_fb_update_rect_linear below. + * This corresponds to the smalled bounding rectangle of the + * latest framebuffer update. + */ +typedef struct { + int xmin, ymin, xmax, ymax; +} FbUpdateRect; + +/* Determine the smallest bounding rectangle of pixels which changed + * between the source (framebuffer) and destination (surface) pixel + * buffers. + * + * Return 0 if there was no change, otherwise, populate '*rect' + * and return 1. + * + * If 'dirty_base' is not 0, it is a physical address that will be + * used to speed-up the check using the VGA dirty bits. In practice + * this is only used if your kernel driver does not implement. + * + * This function assumes that the framebuffers are in linear memory. + * This may change later when we want to support larger framebuffers + * that exceed the max DMA aperture size though. + */ +static int +compute_fb_update_rect_linear(FbUpdateState* fbs, + uint32_t dirty_base, + FbUpdateRect* rect) +{ + int yy; + int width = fbs->width; + const uint8_t* src_line = fbs->src_pixels; + uint8_t* dst_line = fbs->dst_pixels; + uint32_t dirty_addr = dirty_base; + rect->xmin = rect->ymin = INT_MAX; + rect->xmax = rect->ymax = INT_MIN; + for (yy = 0; yy < fbs->height; yy++) { + int xx1, xx2; + /* If dirty_addr is != 0, then use it as a physical address to + * use the VGA dirty bits table to speed up the detection of + * changed pixels. + */ + if (dirty_addr != 0) { + int dirty = 0; + int len = fbs->src_pitch; + + while (len > 0) { + int len2 = TARGET_PAGE_SIZE - (dirty_addr & (TARGET_PAGE_SIZE-1)); + + if (len2 > len) + len2 = len; + + dirty |= cpu_physical_memory_get_dirty(dirty_addr, VGA_DIRTY_FLAG); + dirty_addr += len2; + len -= len2; + } + + if (!dirty) { /* this line was not modified, skip to next one */ + goto NEXT_LINE; + } + } + + if (fbs->src_format->bytes_per_pixel != fbs->dst_format->bytes_per_pixel) { + if (fbs->src_format->bytes_per_pixel == 2) { + const uint16_t* src = (const uint16_t*) src_line; + uint32_t* dst = (uint32_t*) dst_line; + + xx1 = 0; + DUFF4(width, { + if (convert_pix(src[xx1], fbs->dst_format, fbs->src_format) != dst[xx1]) { + break; + } + xx1++; + }); + if (xx1 == width) { + goto NEXT_LINE; + } + xx2 = width-1; + DUFF4(xx2-xx1,{ + if (convert_pix(src[xx2], fbs->dst_format, fbs->src_format) != dst[xx2]) { + break; + } + xx2--; + }); +#ifdef HOST_WORDS_BIGENDIAN + /* Convert the guest little-endian pixels into big-endian ones */ + int xx = xx1; + DUFF4(xx2-xx1+1,{ + uint32_t spix = convert_pix(src[xx], fbs->dst_format, fbs->src_format); + spix = (spix << 16) | (spix >> 16); + spix = ((spix << 8) & 0xff00ff00) | ((spix >> 8) & 0x00ff00ff); + dst[xx] = spix; + xx++; + }) +#else + int xx; + for (xx=xx1; xx <= xx2; xx++) { + dst[xx] = convert_pix(src[xx], fbs->dst_format, fbs->src_format); + } +#endif + } + else { + const uint32_t* src = (const uint32_t*) src_line; + uint16_t* dst = (uint16_t*) dst_line; + + xx1 = 0; + DUFF4(width, { + if (convert_pix(src[xx1], fbs->dst_format, fbs->src_format) != dst[xx1]) { + break; + } + xx1++; + }); + if (xx1 == width) { + goto NEXT_LINE; + } + xx2 = width-1; + DUFF4(xx2-xx1,{ + if (convert_pix(src[xx2], fbs->dst_format, fbs->src_format) != dst[xx2]) { + break; + } + xx2--; + }); +#ifdef HOST_WORDS_BIGENDIAN + /* Convert the guest little-endian pixels into big-endian ones */ + int xx = xx1; + DUFF4(xx2-xx1+1,{ + uint32_t spix = convert_pix(src[xx], fbs->dst_format, fbs->src_format); + dst[xx] = (uint16_t)((spix << 8) | (spix >> 8)); + xx++; + }); +#else + int xx; + for (xx=xx1; xx <= xx2; xx++) { + dst[xx] = convert_pix(src[xx], fbs->dst_format, fbs->src_format); + } +#endif + } + if (xx1 < width) { + if (xx1 < rect->xmin) rect->xmin = xx1; + if (xx2 > rect->xmax) rect->xmax = xx2; + if (yy < rect->ymin) rect->ymin = yy; + if (yy > rect->ymax) rect->ymax = yy; + } + goto NEXT_LINE; + } + + /* Then compute actual bounds of the changed pixels, while + * copying them from 'src' to 'dst'. This depends on the pixel depth. + */ + switch (fbs->bytes_per_pixel) { + case 2: + { + const uint16_t* src = (const uint16_t*) src_line; + uint16_t* dst = (uint16_t*) dst_line; + + xx1 = 0; + DUFF4(width, { + if (src[xx1] != dst[xx1]) + break; + xx1++; + }); + if (xx1 == width) { + break; + } + xx2 = width-1; + DUFF4(xx2-xx1, { + if (src[xx2] != dst[xx2]) + break; + xx2--; + }); +#ifdef HOST_WORDS_BIGENDIAN + /* Convert the guest little-endian pixels into big-endian ones */ + int xx = xx1; + DUFF4(xx2-xx1+1,{ + unsigned spix = src[xx]; + dst[xx] = (uint16_t)((spix << 8) | (spix >> 8)); + xx++; + }); +#else + memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*2 ); +#endif + break; + } + + case 3: + { + xx1 = 0; + DUFF4(width, { + int xx = xx1*3; + if (src_line[xx+0] != dst_line[xx+0] || + src_line[xx+1] != dst_line[xx+1] || + src_line[xx+2] != dst_line[xx+2]) { + break; + } + xx1 ++; + }); + if (xx1 == width) { + break; + } + xx2 = width-1; + DUFF4(xx2-xx1,{ + int xx = xx2*3; + if (src_line[xx+0] != dst_line[xx+0] || + src_line[xx+1] != dst_line[xx+1] || + src_line[xx+2] != dst_line[xx+2]) { + break; + } + xx2--; + }); + memcpy( dst_line+xx1*3, src_line+xx1*3, (xx2-xx1+1)*3 ); + break; + } + + case 4: + { + const uint32_t* src = (const uint32_t*) src_line; + uint32_t* dst = (uint32_t*) dst_line; + + xx1 = 0; + DUFF4(width, { + if (src[xx1] != dst[xx1]) { + break; + } + xx1++; + }); + if (xx1 == width) { + break; + } + xx2 = width-1; + DUFF4(xx2-xx1,{ + if (src[xx2] != dst[xx2]) { + break; + } + xx2--; + }); +#ifdef HOST_WORDS_BIGENDIAN + /* Convert the guest little-endian pixels into big-endian ones */ + int xx = xx1; + DUFF4(xx2-xx1+1,{ + uint32_t spix = src[xx]; + spix = (spix << 16) | (spix >> 16); + spix = ((spix << 8) & 0xff00ff00) | ((spix >> 8) & 0x00ff00ff); + dst[xx] = spix; + xx++; + }) +#else + memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*4 ); +#endif + break; + } + default: + return 0; + } + /* Update bounds if pixels on this line were modified */ + if (xx1 < width) { + if (xx1 < rect->xmin) rect->xmin = xx1; + if (xx2 > rect->xmax) rect->xmax = xx2; + if (yy < rect->ymin) rect->ymin = yy; + if (yy > rect->ymax) rect->ymax = yy; + } + NEXT_LINE: + src_line += fbs->src_pitch; + dst_line += fbs->dst_pitch; + } + + if (rect->ymin > rect->ymax) { /* nothing changed */ + return 0; + } + + /* Always clear the dirty VGA bits */ + cpu_physical_memory_reset_dirty(dirty_base + rect->ymin * fbs->src_pitch, + dirty_base + (rect->ymax+1)* fbs->src_pitch, + VGA_DIRTY_FLAG); + return 1; +} + + +static void goldfish_fb_update_display(void *opaque) +{ + GoldfishFBDevice *s = (GoldfishFBDevice *)opaque; + uint32_t base; + uint8_t* dst_line; + uint8_t* src_line; + int full_update = 0; + int width, height, pitch; + + base = s->fb_base; + if(base == 0) + return; + + if((s->int_enable & FB_INT_VSYNC) && !(s->int_status & FB_INT_VSYNC)) { + s->int_status |= FB_INT_VSYNC; + goldfish_device_set_irq(&s->dev, 0, 1); + } + + if(s->need_update) { + full_update = 1; + if(s->need_int) { + s->int_status |= FB_INT_BASE_UPDATE_DONE; + if(s->int_enable & FB_INT_BASE_UPDATE_DONE) + goldfish_device_set_irq(&s->dev, 0, 1); + } + s->need_int = 0; + s->need_update = 0; + } + + src_line = qemu_get_ram_ptr( base ); + + dst_line = s->ds->surface->data; + pitch = s->ds->surface->linesize; + width = s->ds->surface->width; + height = s->ds->surface->height; + + FbUpdateState fbs; + FbUpdateRect rect; + + fbs.width = width; + fbs.height = height; + fbs.dst_pixels = dst_line; + fbs.dst_pitch = pitch; + fbs.dst_format = &s->ds->surface->pf; + fbs.bytes_per_pixel = goldfish_fb_get_bytes_per_pixel(s); + + fbs.src_pixels = src_line; + //fbs.src_pitch = width*s->ds->surface->pf.bytes_per_pixel; + /* the kernel only works with RGB 565 at this time */ + PixelFormat rgb_565_pf = qemu_default_pixelformat(16); + fbs.src_pitch = width * rgb_565_pf.bytes_per_pixel; + fbs.src_format = &rgb_565_pf; + + +#if STATS + if (full_update) + stats_full_updates += 1; + if (++stats_counter == 120) { + stats_total += stats_counter; + stats_total_full_updates += stats_full_updates; + + printf( "full update stats: peak %.2f %% total %.2f %%\n", + stats_full_updates*100.0/stats_counter, + stats_total_full_updates*100.0/stats_total ); + + stats_counter = 0; + stats_full_updates = 0; + } +#endif /* STATS */ + + if (s->blank) + { + memset( dst_line, 0, height*pitch ); + rect.xmin = 0; + rect.ymin = 0; + rect.xmax = width-1; + rect.ymax = height-1; + } + else + { + if (full_update) { /* don't use dirty-bits optimization */ + base = 0; + } + if (compute_fb_update_rect_linear(&fbs, base, &rect) == 0) { + return; + } + } + + rect.xmax += 1; + rect.ymax += 1; +#if 0 + printf("goldfish_fb_update_display (y:%d,h:%d,x=%d,w=%d)\n", + rect.ymin, rect.ymax-rect.ymin, rect.xmin, rect.xmax-rect.xmin); +#endif + + dpy_update(s->ds, rect.xmin, rect.ymin, rect.xmax-rect.xmin, rect.ymax-rect.ymin); +} + +static void goldfish_fb_invalidate_display(void * opaque) +{ + // is this called? + GoldfishFBDevice *s = (GoldfishFBDevice *)opaque; + s->need_update = 1; +} + +static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset) +{ + uint32_t ret; + GoldfishFBDevice *s = (GoldfishFBDevice *)opaque; + + switch(offset) { + case FB_GET_WIDTH: + ret = ds_get_width(s->ds); + //printf("FB_GET_WIDTH => %d\n", ret); + return ret; + + case FB_GET_HEIGHT: + ret = ds_get_height(s->ds); + //printf( "FB_GET_HEIGHT = %d\n", ret); + return ret; + + case FB_INT_STATUS: + ret = s->int_status & s->int_enable; + if(ret) { + s->int_status &= ~ret; + goldfish_device_set_irq(&s->dev, 0, 0); + } + return ret; + + case FB_GET_PHYS_WIDTH: + ret = pixels_to_mm( ds_get_width(s->ds), s->dpi ); + //printf( "FB_GET_PHYS_WIDTH => %d\n", ret ); + return ret; + + case FB_GET_PHYS_HEIGHT: + ret = pixels_to_mm( ds_get_height(s->ds), s->dpi ); + //printf( "FB_GET_PHYS_HEIGHT => %d\n", ret ); + return ret; + + case FB_GET_FORMAT: + return goldfish_fb_get_pixel_format(s); + + default: + cpu_abort (cpu_single_env, "goldfish_fb_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_fb_write(void *opaque, target_phys_addr_t offset, + uint32_t val) +{ + GoldfishFBDevice *s = (GoldfishFBDevice *)opaque; + + switch(offset) { + case FB_INT_ENABLE: + s->int_enable = val; + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + break; + case FB_SET_BASE: { + int need_resize = !s->base_valid; + s->fb_base = val; + s->int_status &= ~FB_INT_BASE_UPDATE_DONE; + s->need_update = 1; + s->need_int = 1; + s->base_valid = 1; + if(s->set_rotation != s->rotation) { + //printf("FB_SET_BASE: rotation : %d => %d\n", s->rotation, s->set_rotation); + s->rotation = s->set_rotation; + need_resize = 1; + } + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + if (need_resize) { + //printf("FB_SET_BASE: need resize (rotation=%d)\n", s->rotation ); + dpy_resize(s->ds); + } + } break; + case FB_SET_ROTATION: + //printf( "FB_SET_ROTATION %d\n", val); + s->set_rotation = val; + break; + case FB_SET_BLANK: + s->blank = val; + s->need_update = 1; + break; + default: + cpu_abort (cpu_single_env, "goldfish_fb_write: Bad offset %x\n", offset); + } +} + +static CPUReadMemoryFunc *goldfish_fb_readfn[] = { + goldfish_fb_read, + goldfish_fb_read, + goldfish_fb_read +}; + +static CPUWriteMemoryFunc *goldfish_fb_writefn[] = { + goldfish_fb_write, + goldfish_fb_write, + goldfish_fb_write +}; + +static int goldfish_fb_init(GoldfishDevice *dev) +{ + GoldfishFBDevice *s = (GoldfishFBDevice *)dev; + + s->ds = graphic_console_init(goldfish_fb_update_display, + goldfish_fb_invalidate_display, + NULL, + NULL, + s); + + s->dpi = 165; /* XXX: Find better way to get actual value ! */ + + /* IMPORTANT: DO NOT COMPUTE s->pixel_format and s->bytes_per_pixel + * here because the display surface is going to change later. + */ + s->bytes_per_pixel = 0; + s->pixel_format = -1; + + //goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s); + + //register_savevm( NULL, "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION, + // goldfish_fb_save, goldfish_fb_load, s); + + return 0; +} + +DeviceState *goldfish_fb_create(GoldfishBus *gbus, int id) +{ + DeviceState *dev; + char *name = (char *)"goldfish_fb"; + + dev = qdev_create(&gbus->bus, name); + qdev_prop_set_string(dev, "name", name); + qdev_prop_set_uint32(dev, "id", id); + qdev_init_nofail(dev); + + return dev; +} + +static GoldfishDeviceInfo goldfish_fb_info = { + .init = goldfish_fb_init, + .readfn = goldfish_fb_readfn, + .writefn = goldfish_fb_writefn, + .qdev.name = "goldfish_fb", + .qdev.size = sizeof(GoldfishFBDevice), + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("base", GoldfishDevice, base, 0), + DEFINE_PROP_UINT32("id", GoldfishDevice, id, -1), + DEFINE_PROP_UINT32("size", GoldfishDevice, size, 0x1000), + DEFINE_PROP_UINT32("irq", GoldfishDevice, irq, 0), + DEFINE_PROP_UINT32("irq_count", GoldfishDevice, irq_count, 1), + DEFINE_PROP_STRING("name", GoldfishDevice, name), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void goldfish_fb_register(void) +{ + goldfish_bus_register_withprop(&goldfish_fb_info); +} +device_init(goldfish_fb_register); -- 1.7.4.1 --00248c7119dd0ae82104ab14da30 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable

Handles the framebuffer for the Android kernel.

Also manages pixel conversions as the Android kernel only= works with the RGB_565 format.

Signed-off-by: Pat= rick Jackson <PatrickSJackson@gmail.com>
---
=A0Makefile.target =A0 =A0 =A0| =A0 =A02 +-
= =A0hw/android_arm.c =A0 =A0 | =A0 =A01 +
=A0hw/goldfish_device.h = | =A0 =A01 +
=A0hw/goldfish_fb.c =A0 =A0 | =A0740 +++++++++++++++= +++++++++++++++++++++++++++++++++++
=A04 files changed, 743 insertions(+), 1 deletions(-)
=A0cre= ate mode 100644 hw/goldfish_fb.c

diff --git a/Make= file.target b/Makefile.target
index ea9a741..020aba6 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -36= 1,7 +361,7 @@ obj-arm-y +=3D vexpress.o
=A0obj-arm-y +=3D stronga= rm.o
=A0obj-arm-y +=3D collie.o
=A0obj-arm-y +=3D andro= id_arm.o goldfish_device.o goldfish_interrupt.o goldfish_timer.o
-obj-arm-y +=3D goldfish_tty.o goldfish_nand.o
+obj-arm-y += =3D goldfish_tty.o goldfish_nand.o goldfish_fb.o
=A0
= =A0obj-sh4-y =3D shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
=A0obj-sh4-y +=3D sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/hw/android_arm.c b/hw/android_arm.c
index bf49b= 74..38fd3d2 100644
--- a/hw/android_arm.c
+++ b/hw/andr= oid_arm.c
@@ -65,6 +65,7 @@ static void android_arm_init_(ram_add= r_t ram_size,
=A0 =A0 =A0 =A0 =A0}
=A0 =A0 =A0}
=A0
+ = =A0 =A0goldfish_fb_create(gbus, 0);
=A0 =A0 =A0goldfish_nand_crea= te(gbus);
=A0
=A0 =A0 =A0info.ram_size =A0 =A0 =A0 =A0= =3D ram_size;
diff --git a/hw/goldfish_device.h b/hw/goldfish_dev= ice.h
index 91d74fd..1ec5646 100644
--- a/hw/goldfish_device.h
+++ b/hw/goldfish_device.h
@@ -47,6 +47,7 @@ DeviceState *= goldfish_timer_create(GoldfishBus *gbus, uint32_t base, int irq);
=A0DeviceState *goldfish_rtc_create(GoldfishBus *gbus);
=A0D= eviceState *goldfish_tty_create(GoldfishBus *gbus, CharDriverState *cs, int= id, uint32_t base, int irq);
=A0DeviceState *goldfish_nand_creat= e(GoldfishBus *gbus);
+DeviceState *goldfish_fb_create(GoldfishBus *gbus, int id);
=A0
=A0/* Global functions provided by Goldfish devices */
=
=A0void goldfish_bus_register_withprop(GoldfishDeviceInfo *info);
diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c
new file mode 10= 0644
index 0000000..1b45ba4
--- /dev/null
+++= b/hw/goldfish_fb.c
@@ -0,0 +1,740 @@
+/* Copyright (C)= 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU= General Public
+** License version 2, as published by the Free S= oftware Foundation, and
+** may be copied, distributed, and modif= ied under those terms.
+**
+** This program is distributed in the hope that it will= be useful,
+** but WITHOUT ANY WARRANTY; without even the implie= d warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PUR= POSE. =A0See the
+** GNU General Public License for more details.
+*/
+#include "goldfish_device.h"
+#include "consol= e.h"
+
+#define =A0DUFF4(_count,_stmnt) =A0\
+ =A0 =A0({ \
+ =A0 =A0 =A0 =A0int =A0 __count =3D (_count);= \
+ =A0 =A0 =A0 =A0int =A0 __n =A0 =A0 =3D (__count +3)/4; \
+ =A0 =A0 =A0 =A0switch (__count & 3) { \
+ =A0 =A0 = =A0 =A0case 0: do { _stmnt; \
+ =A0 =A0 =A0 =A0case 3: =A0 =A0 = =A0_stmnt; \
+ =A0 =A0 =A0 =A0case 2: =A0 =A0 =A0_stmnt; \
+ =A0 =A0 =A0 = =A0case 1: =A0 =A0 =A0_stmnt; \
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= } while (--__n > 0); \
+ =A0 =A0 =A0 =A0} \
+ =A0 = =A0})
+
+/* These values *must* match the platform defi= nitions found under
+ * hardware/libhardware/include/hardware/hardware.h
+ */
+enum {
+ =A0 =A0HAL_PIXEL_FORMAT_RGBA_8888 =A0 =A0 =A0 = =A0 =A0=3D 1,
+ =A0 =A0HAL_PIXEL_FORMAT_RGBX_8888 =A0 =A0 =A0 =A0= =A0=3D 2,
+ =A0 =A0HAL_PIXEL_FORMAT_RGB_888 =A0 =A0 =A0 =A0 =A0 = =A0=3D 3,
+ =A0 =A0HAL_PIXEL_FORMAT_RGB_565 =A0 =A0 =A0 =A0 =A0 =A0=3D 4,
<= div>+ =A0 =A0HAL_PIXEL_FORMAT_BGRA_8888 =A0 =A0 =A0 =A0 =A0=3D 5,
+ =A0 =A0HAL_PIXEL_FORMAT_RGBA_5551 =A0 =A0 =A0 =A0 =A0=3D 6,
+ = =A0 =A0HAL_PIXEL_FORMAT_RGBA_4444 =A0 =A0 =A0 =A0 =A0=3D 7,
+};
+
+enum {
+ =A0 =A0FB_GET_WIDTH =A0 = =A0 =A0 =A0=3D 0x00,
+ =A0 =A0FB_GET_HEIGHT =A0 =A0 =A0 =3D 0x04,=
+ =A0 =A0FB_INT_STATUS =A0 =A0 =A0 =3D 0x08,
+ =A0 =A0= FB_INT_ENABLE =A0 =A0 =A0 =3D 0x0c,
+ =A0 =A0FB_SET_BASE =A0 =A0 =A0 =A0 =3D 0x10,
+ =A0 =A0FB_SET_RO= TATION =A0 =A0 =3D 0x14,
+ =A0 =A0FB_SET_BLANK =A0 =A0 =A0 =A0=3D= 0x18,
+ =A0 =A0FB_GET_PHYS_WIDTH =A0 =3D 0x1c,
+ =A0 = =A0FB_GET_PHYS_HEIGHT =A0=3D 0x20,
+ =A0 =A0FB_GET_FORMAT =A0 =A0= =A0 =3D 0x24,
+
+ =A0 =A0FB_INT_VSYNC =A0 =A0 =A0 =A0 =A0 =A0 =3D 1U <&= lt; 0,
+ =A0 =A0FB_INT_BASE_UPDATE_DONE =A0=3D 1U << 1
+};
+
+typedef struct GoldfishFBDevice {
+ =A0 =A0GoldfishDevice dev;
+ =A0 =A0DisplayState* =A0ds;
+ =A0 =A0int =A0 =A0 =A0pixel_= format;
+ =A0 =A0int =A0 =A0 =A0bytes_per_pixel;
+ =A0 = =A0uint32_t fb_base;
+ =A0 =A0uint32_t base_valid : 1;
= + =A0 =A0uint32_t need_update : 1;
+ =A0 =A0uint32_t need_int : 1;
+ =A0 =A0uint32_t set_rotati= on : 2;
+ =A0 =A0uint32_t blank : 1;
+ =A0 =A0uint32_t = int_status;
+ =A0 =A0uint32_t int_enable;
+ =A0 =A0int = =A0 =A0 =A0rotation; =A0 /* 0, 1, 2 or 3 */
+ =A0 =A0int =A0 =A0 =A0dpi;
+} GoldfishFBDevice;
= +
+/* Type used to record a mapping from display surface pixel fo= rmat to
+ * HAL pixel format */
+typedef struct {
=
+ =A0 =A0int =A0 =A0pixel_format; /* HAL pixel format */
+ =A0 =A0uint8_t bits;
+ =A0 =A0uint8_t bytes;
+ = =A0 =A0uint32_t rmask, gmask, bmask, amask;
+} FbConfig;
+
+
+/* Return the pixel format of the current frameb= uffer, based on
+ * the current display surface's pixel format.
+ *
+ * Note that you should not call this function from the device initi= alization
+ * function, because the display surface will change f= ormat before the kernel
+ * start.
+ */
+static int goldfish_fb_get_pixel_= format(GoldfishFBDevice *s)
+{
+ =A0 =A0if (s->pixel= _format >=3D 0) {
+ =A0 =A0 =A0 =A0return s->pixel_format;<= /div>
+ =A0 =A0}
+ =A0 =A0static const FbConfig fb_configs[] =3D {
+ =A0 =A0 =A0 =A0{ HAL_PIXEL_FORMAT_RGB_565, 16, 2, 0xf800, 0x7e0, 0x= 1f, 0x0 },
+ =A0 =A0 =A0 =A0{ HAL_PIXEL_FORMAT_RGBX_8888, 32, 4, = 0xff0000, 0xff00, 0xff, 0x0 },
+ =A0 =A0 =A0 =A0{ HAL_PIXEL_FORMAT_RGBA_8888, 32, 4, 0xff0000, 0xff00= , 0xff, 0xff000000 },
+ =A0 =A0 =A0 =A0{ -1, }
+ =A0 = =A0};
+
+ =A0 =A0/* Determine HAL pixel format value ba= sed on s->ds */
+ =A0 =A0struct PixelFormat* pf =3D &s->ds->surface->pf;<= /div>
+#if 0
+ =A0 =A0printf("%s:%d: display surface,pix= el format:\n", __FUNCTION__, __LINE__);
+ =A0 =A0printf(&quo= t; =A0bits/pixel: =A0%d\n", pf->bits_per_pixel);
+ =A0 =A0printf(" =A0bytes/pixel: %d\n", pf->bytes_per_pi= xel);
+ =A0 =A0printf(" =A0depth: =A0 =A0 =A0 %d\n", pf= ->depth);
+ =A0 =A0printf(" =A0red: =A0 =A0 =A0 =A0 bits= =3D%d mask=3D0x%x shift=3D%d max=3D0x%x\n",
+ =A0 =A0 =A0 =A0pf->rbits, pf->rmask, pf->rshift, pf->rma= x);
+ =A0 =A0printf(" =A0green: =A0 =A0 =A0 bits=3D%d mask= =3D0x%x shift=3D%d max=3D0x%x\n",
+ =A0 =A0 =A0 =A0pf->gb= its, pf->gmask, pf->gshift, pf->gmax);
+ =A0 =A0printf(" =A0blue: =A0 =A0 =A0 =A0bits=3D%d mask=3D0x%x s= hift=3D%d max=3D0x%x\n",
+ =A0 =A0 =A0 =A0pf->bbits, pf-&= gt;bmask, pf->bshift, pf->bmax);
+ =A0 =A0printf(" =A0= alpha: =A0 =A0 =A0 bits=3D%d mask=3D0x%x shift=3D%d max=3D0x%x\n",
+ =A0 =A0 =A0 =A0pf->abits, pf->amask, pf->ashift, pf->ama= x);
+#endif
+
+ =A0 =A0s->bytes_per_pixel = =3D pf->bytes_per_pixel;
+ =A0 =A0int nn;
+ =A0 =A0f= or (nn =3D 0; fb_configs[nn].pixel_format >=3D 0; nn++) {
+ =A0 =A0 =A0 =A0const FbConfig* fbc =3D &fb_configs[nn];
+ =A0 =A0 =A0 =A0if (pf->bits_per_pixel =3D=3D fbc->bits &&=
+ =A0 =A0 =A0 =A0 =A0 =A0pf->bytes_per_pixel =3D=3D fbc->b= ytes &&
+ =A0 =A0 =A0 =A0 =A0 =A0pf->rmask =3D=3D fbc-= >rmask &&
+ =A0 =A0 =A0 =A0 =A0 =A0pf->gmask =3D=3D fbc->gmask &&<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0pf->bmask =3D=3D fbc->bmask &&= amp;
+ =A0 =A0 =A0 =A0 =A0 =A0pf->amask =3D=3D fbc->amask) = {
+ =A0 =A0 =A0 =A0 =A0 =A0/* We found it */
+ =A0 =A0 =A0 =A0 =A0 =A0s->pixel_format =3D fbc->pixel_format;<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0return s->pixel_format;
+ = =A0 =A0 =A0 =A0}
+ =A0 =A0}
+ =A0 =A0fprintf(stderr, &q= uot;%s:%d: Unsupported display pixel format (depth=3D%d, bytespp=3D%d, bits= pp=3D%d)\n",
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__FUNCTION__, __LINE__,
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pf->depth,
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0pf->bytes_per_pixel,
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0pf->bits_per_pixel);
+ =A0 =A0exit(1);
+ =A0 =A0return -1;
+}
+
+static int goldfish= _fb_get_bytes_per_pixel(GoldfishFBDevice *s)
+{
+ =A0 = =A0if (s->pixel_format < 0) {
+ =A0 =A0 =A0 =A0(void) goldf= ish_fb_get_pixel_format(s);
+ =A0 =A0}
+ =A0 =A0return s->bytes_per_pixel;
= +}
+
+static int
+pixels_to_mm(int =A0pixels,= int dpi)
+{
+ =A0 =A0/* dpi =3D dots / inch
= + =A0 =A0** inch =3D dots / dpi
+ =A0 =A0** mm / 25.4 =3D dots / dpi
+ =A0 =A0** mm =3D (dot= s * 25.4)/dpi
+ =A0 =A0*/
+ =A0 =A0return (int)(0.5 + 2= 5.4 * pixels =A0/ dpi);
+}
+
+static uint32_t= convert_pix(uint32_t rgb, struct PixelFormat* pf_out, struct PixelFormat* = pf_in)
+{
+ =A0 =A0// Pixel conversion
+ =A0 =A0uint8_t r= ed =A0 =3D (rgb & pf_in->rmask) >> pf_in->rshift;
+ =A0 =A0uint8_t green =3D (rgb & pf_in->gmask) >> pf_in->= gshift;
+ =A0 =A0uint8_t blue =A0=3D (rgb & pf_in->bmask) >> pf_in->= ;bshift;
+ =A0 =A0red =A0 <<=3D pf_out->rbits - pf_in-&g= t;rbits;
+ =A0 =A0green <<=3D pf_out->gbits - pf_in->= gbits;
+ =A0 =A0blue =A0<<=3D pf_out->bbits - pf_in->bbits;
+ =A0 =A0return (blue << pf_out->bshift) | (green << pf= _out->gshift) | (red << pf_out->rshift);
+}
+
+
+#define =A0STATS =A00
+
+#if = STATS
+static int =A0 stats_counter;
+static long =A0stats_total;<= /div>
+static int =A0 stats_full_updates;
+static long =A0sta= ts_total_full_updates;
+#endif
+
+/* This str= ucture is used to hold the inputs for
+ * compute_fb_update_rect_linear below.
+ * This correspond= s to the source framebuffer and destination
+ * surface pixel buf= fers.
+ */
+typedef struct {
+ =A0 =A0int =A0= =A0 =A0 =A0 =A0 =A0width;
+ =A0 =A0int =A0 =A0 =A0 =A0 =A0 =A0height;
+ =A0 =A0int =A0= =A0 =A0 =A0 =A0 =A0bytes_per_pixel;
+ =A0 =A0const uint8_t* src_= pixels;
+ =A0 =A0int =A0 =A0 =A0 =A0 =A0 =A0src_pitch;
= + =A0 =A0PixelFormat* =A0 src_format;
+ =A0 =A0uint8_t* =A0 =A0 = =A0 dst_pixels;
+ =A0 =A0int =A0 =A0 =A0 =A0 =A0 =A0dst_pitch;
+ =A0 =A0Pixe= lFormat* =A0 dst_format;
+} FbUpdateState;
+
= +/* This structure is used to hold the outputs for
+ * compute_fb= _update_rect_linear below.
+ * This corresponds to the smalled bounding rectangle of the
+ * latest framebuffer update.
+ */
+typedef struct {=
+ =A0 =A0int xmin, ymin, xmax, ymax;
+} FbUpdateRect;<= /div>
+
+/* Determine the smallest bounding rectangle of pixels wh= ich changed
+ * between the source (framebuffer) and destination = (surface) pixel
+ * buffers.
+ *
+ * Return 0= if there was no change, otherwise, populate '*rect'
+ * and return 1.
+ *
+ * If 'dirty_base' = is not 0, it is a physical address that will be
+ * used to speed= -up the check using the VGA dirty bits. In practice
+ * this is o= nly used if your kernel driver does not implement.
+ *
+ * This function assumes that the framebuffers are in l= inear memory.
+ * This may change later when we want to support l= arger framebuffers
+ * that exceed the max DMA aperture size thou= gh.
+ */
+static int
+compute_fb_update_rect_linear(Fb= UpdateState* =A0fbs,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0uint32_t =A0 =A0 =A0 =A0dirty_base,
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0FbUpdateRect* =A0 rect)<= /div>
+{
+ =A0 =A0int =A0yy;
+ =A0 =A0int =A0width =3D f= bs->width;
+ =A0 =A0const uint8_t* src_line =3D fbs->src_pi= xels;
+ =A0 =A0uint8_t* =A0 =A0 =A0 dst_line =3D fbs->dst_pixe= ls;
+ =A0 =A0uint32_t =A0 =A0 =A0 dirty_addr =3D dirty_base;
+ =A0 =A0rect->xmin =3D rect->ymin =3D INT_MAX;
+ =A0 = =A0rect->xmax =3D rect->ymax =3D INT_MIN;
+ =A0 =A0for (yy = =3D 0; yy < fbs->height; yy++) {
+ =A0 =A0 =A0 =A0int xx1, = xx2;
+ =A0 =A0 =A0 =A0/* If dirty_addr is !=3D 0, then use it as = a physical address to
+ =A0 =A0 =A0 =A0 * use the VGA dirty bits table to speed up the detec= tion of
+ =A0 =A0 =A0 =A0 * changed pixels.
+ =A0 =A0 = =A0 =A0 */
+ =A0 =A0 =A0 =A0if (dirty_addr !=3D 0) {
+ = =A0 =A0 =A0 =A0 =A0 =A0int =A0dirty =3D 0;
+ =A0 =A0 =A0 =A0 =A0 =A0int =A0len =A0 =3D fbs->src_pitch;
+
+ =A0 =A0 =A0 =A0 =A0 =A0while (len > 0) {
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int =A0len2 =3D TARGET_PAGE_SIZE - (dirty_ad= dr & (TARGET_PAGE_SIZE-1));
+
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (len2 > len)
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0len2 =3D len;
+
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dirty |=3D cpu_physical_memory_get_dirty(dir= ty_addr, VGA_DIRTY_FLAG);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dirty_= addr =A0+=3D len2;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0len =A0 =A0 =A0 =A0 -=3D len2;
<= div>+ =A0 =A0 =A0 =A0 =A0 =A0}
+
+ =A0 =A0 =A0 =A0 =A0 = =A0if (!dirty) { /* this line was not modified, skip to next one */
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto NEXT_LINE;
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0}
+
+ =A0 =A0 =A0 =A0if (fbs->src_format->bytes_per_pixel !=3D fbs->= ;dst_format->bytes_per_pixel) {
+ =A0 =A0 =A0 =A0 =A0 =A0if (f= bs->src_format->bytes_per_pixel =3D=3D 2) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const uint16_t* src =3D (const uint16= _t*) src_line;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0uint32_t* =A0 =A0= =A0 dst =3D (uint32_t*) dst_line;
+
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0xx1 =3D 0;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DUFF4(= width, {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (convert_pix(src[xx1], fbs= ->dst_format, fbs->src_format) !=3D dst[xx1]) {
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0xx1++;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0});
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0if (xx1 =3D=3D width) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0goto NEXT_LINE;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0xx2 =3D width-1;
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0DUFF4(xx2-xx1,{
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (convert_pix(src[xx2], fbs= ->dst_format, fbs->src_format) !=3D dst[xx2]) {
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0xx2--;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0});
+#ifdef HOST_WORDS_BIGE= NDIAN
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Convert the guest littl= e-endian pixels into big-endian ones */
+ =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0int xx =3D xx1;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DUFF4(xx= 2-xx1+1,{
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0uint32_t =A0 spix =3D convert= _pix(src[xx], fbs->dst_format, fbs->src_format);
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0spix =3D (spix << 16) | (spix >>= 16);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0spix =3D ((spix &l= t;< 8) & 0xff00ff00) | ((spix >> 8) & 0x00ff00ff);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dst[xx] =3D spix;
+= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0xx++;
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0})
+#else
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0int xx;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0for (xx=3Dxx1; xx <= ;=3D xx2; xx++) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dst[xx] =3D convert_pix(src[x= x], fbs->dst_format, fbs->src_format);
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0}
+#endif
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0else {
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0const uint32_t* src =3D (const uint32_t*) src_line;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0uint16_t* =A0 =A0 =A0 dst =3D (uint16= _t*) dst_line;
+
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0xx1 = =3D 0;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DUFF4(width, {
= + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (convert_pix(src[xx1], fbs->= dst_format, fbs->src_format) !=3D dst[xx1]) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0xx1++;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0});
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (xx1 =3D=3D width) {
= + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto NEXT_LINE;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0xx2 =3D width-1;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DUFF4(x= x2-xx1,{
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (convert_pix= (src[xx2], fbs->dst_format, fbs->src_format) !=3D dst[xx2]) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0xx2--;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0});
+#ifdef HOST_WORDS_BIGENDIAN
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0/* Convert the guest little-endian pixels into big-endian ones */
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int xx =3D xx1;
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0DUFF4(xx2-xx1+1,{
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0uint32_t =A0 spix =3D convert_pix(src[xx], fbs->dst_f= ormat, fbs->src_format);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0dst[xx] =3D (uint16_t)((spix << 8) | (spix >> 8));
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0xx++;
+ =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0});
+#else
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0int xx;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0for (xx=3Dxx1= ; xx <=3D xx2; xx++) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0dst[xx] =3D convert_pix(src[xx], fbs->dst_format, fbs->src_format)= ;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
+#endif
+ =A0 = =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0if (xx1 < width)= {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (xx1 < rect->xmin) r= ect->xmin =3D xx1;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (xx2 &g= t; rect->xmax) rect->xmax =3D xx2;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (yy < rect->ymin) rect->y= min =3D yy;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (yy > rect->= ;ymax) rect->ymax =3D yy;
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0goto NEXT_LINE;
+ =A0 =A0 =A0 =A0}
+
+ =A0 =A0 =A0 =A0/* Then compute actual bounds of the chan= ged pixels, while
+ =A0 =A0 =A0 =A0 * copying them from 'src&= #39; to 'dst'. This depends on the pixel depth.
+ =A0 =A0= =A0 =A0 */
+ =A0 =A0 =A0 =A0switch (fbs->bytes_per_pixel) {
+ =A0 =A0 =A0= =A0case 2:
+ =A0 =A0 =A0 =A0{
+ =A0 =A0 =A0 =A0 =A0 = =A0const uint16_t* src =3D (const uint16_t*) src_line;
+ =A0 =A0 = =A0 =A0 =A0 =A0uint16_t* =A0 =A0 =A0 dst =3D (uint16_t*) dst_line;
+
+ =A0 =A0 =A0 =A0 =A0 =A0xx1 =3D 0;
+ =A0 =A0 = =A0 =A0 =A0 =A0DUFF4(width, {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if= (src[xx1] !=3D dst[xx1])
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0break;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0xx1++;
+ =A0= =A0 =A0 =A0 =A0 =A0});
+ =A0 =A0 =A0 =A0 =A0 =A0if (xx1 =3D=3D width) {
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0xx2 =3D width-1;
+ =A0 =A0 =A0 =A0 =A0= =A0DUFF4(xx2-xx1, {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (src[xx2= ] !=3D dst[xx2])
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0xx2--;
+ =A0 =A0 =A0 =A0 =A0 =A0});
<= div>+#ifdef HOST_WORDS_BIGENDIAN
+ =A0 =A0 =A0 =A0 =A0 =A0/* Conv= ert the guest little-endian pixels into big-endian ones */
+ =A0 =A0 =A0 =A0 =A0 =A0int xx =3D xx1;
+ =A0 =A0 =A0 =A0 = =A0 =A0DUFF4(xx2-xx1+1,{
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigne= d =A0 spix =3D src[xx];
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dst[xx] = =3D (uint16_t)((spix << 8) | (spix >> 8));
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0xx++;
+ =A0 =A0 =A0 =A0 =A0 =A0}= );
+#else
+ =A0 =A0 =A0 =A0 =A0 =A0memcpy( dst+xx1, src= +xx1, (xx2-xx1+1)*2 );
+#endif
+ =A0 =A0 =A0 =A0 =A0 = =A0break;
+ =A0 =A0 =A0 =A0}
+
+ =A0 =A0 =A0 =A0case 3:
+ =A0 =A0 =A0 =A0{
+ =A0 =A0 = =A0 =A0 =A0 =A0xx1 =3D 0;
+ =A0 =A0 =A0 =A0 =A0 =A0DUFF4(width, {=
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int xx =3D xx1*3;
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (src_line[xx+0] !=3D dst_line[xx+0] ||
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0src_line[xx+1] !=3D dst_line[= xx+1] ||
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0src_line[xx+2] = !=3D dst_line[xx+2]) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0b= reak;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0xx1 ++;
+ =A0 =A0 =A0 =A0 =A0 =A0});
+ =A0 =A0 =A0 =A0 =A0 =A0if (xx= 1 =3D=3D width) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0xx2 =3D wi= dth-1;
+ =A0 =A0 =A0 =A0 =A0 =A0DUFF4(xx2-xx1,{
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0int xx =3D xx2*3;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (src_line[xx+0] !=3D dst_line[xx+0= ] ||
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0src_line[xx+1] !=3D= dst_line[xx+1] ||
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0src_l= ine[xx+2] !=3D dst_line[xx+2]) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0xx2--;
+ =A0 =A0 =A0 =A0 =A0 =A0});
+ =A0 =A0 = =A0 =A0 =A0 =A0memcpy( dst_line+xx1*3, src_line+xx1*3, (xx2-xx1+1)*3 );
+ =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0}
+
+ =A0 =A0 =A0 =A0case 4:
+ =A0 =A0 =A0 =A0{
+ =A0 =A0 =A0 =A0 =A0 =A0const uint32_t* src =3D (const uint32_t*) sr= c_line;
+ =A0 =A0 =A0 =A0 =A0 =A0uint32_t* =A0 =A0 =A0 dst =3D (u= int32_t*) dst_line;
+
+ =A0 =A0 =A0 =A0 =A0 =A0xx1 =3D = 0;
+ =A0 =A0 =A0 =A0 =A0 =A0DUFF4(width, {
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0if (src[xx1] !=3D dst[xx1]) {
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0xx1++;
+ =A0 =A0 =A0 = =A0 =A0 =A0});
+ =A0 =A0 =A0 =A0 =A0 =A0if (xx1 =3D=3D width) {
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0xx2 =3D width-1;
+ =A0 =A0 =A0 =A0 =A0= =A0DUFF4(xx2-xx1,{
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (src[xx2]= !=3D dst[xx2]) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0xx2--;<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0});
+#ifdef HOST_WORDS_BIGENDI= AN
+ =A0 =A0 =A0 =A0 =A0 =A0/* Convert the guest little-endian pi= xels into big-endian ones */
+ =A0 =A0 =A0 =A0 =A0 =A0int xx =3D xx1;
+ =A0 =A0 =A0 =A0 = =A0 =A0DUFF4(xx2-xx1+1,{
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0uint32_= t =A0 spix =3D src[xx];
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0spix =3D= (spix << 16) | (spix >> 16);
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0spix =3D ((spix << 8) & 0xff00ff00) | ((spix >> = 8) & 0x00ff00ff);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dst[xx] =3D spix;
+ =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0xx++;
+ =A0 =A0 =A0 =A0 =A0 =A0})
+#else
+ =A0 =A0 =A0 =A0 =A0 =A0memcpy( dst+xx1, src+xx1, (xx2= -xx1+1)*4 );
+#endif
+ =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0default:
+ =A0= =A0 =A0 =A0 =A0 =A0return 0;
+ =A0 =A0 =A0 =A0}
+ =A0 = =A0 =A0 =A0/* Update bounds if pixels on this line were modified */
+ =A0 =A0 =A0 =A0if (xx1 < width) {
+ =A0 =A0 =A0 =A0 =A0 =A0if (xx1 < rect->xmin) rect->xmin =3D xx1;=
+ =A0 =A0 =A0 =A0 =A0 =A0if (xx2 > rect->xmax) rect->xm= ax =3D xx2;
+ =A0 =A0 =A0 =A0 =A0 =A0if (yy < rect->ymin) r= ect->ymin =3D yy;
+ =A0 =A0 =A0 =A0 =A0 =A0if (yy > rect-&g= t;ymax) rect->ymax =3D yy;
+ =A0 =A0 =A0 =A0}
+ =A0 =A0NEXT_LINE:
+ =A0 =A0 = =A0 =A0src_line +=3D fbs->src_pitch;
+ =A0 =A0 =A0 =A0dst_line= +=3D fbs->dst_pitch;
+ =A0 =A0}
+
+ =A0 = =A0if (rect->ymin > rect->ymax) { /* nothing changed */
+ =A0 =A0 =A0 =A0return 0;
+ =A0 =A0}
+
= + =A0 =A0/* Always clear the dirty VGA bits */
+ =A0 =A0cpu_physi= cal_memory_reset_dirty(dirty_base + rect->ymin * fbs->src_pitch,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0dirty_base + (rect->ymax+1)* fbs->src_pitch,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0VGA_DIRTY_FLAG);
+ =A0 =A0return 1;
+}
+
+
+static void goldfish_fb_update_display(void *opaque)<= /div>
+{
+ =A0 =A0GoldfishFBDevice *s =3D (GoldfishFBDevice *= )opaque;
+ =A0 =A0uint32_t base;
+ =A0 =A0uint8_t* =A0dst_line;
=
+ =A0 =A0uint8_t* =A0src_line;
+ =A0 =A0int full_update =3D = 0;
+ =A0 =A0int =A0width, height, pitch;
+
+ = =A0 =A0base =3D s->fb_base;
+ =A0 =A0if(base =3D=3D 0)
+ =A0 =A0 =A0 =A0return;
+
+ =A0 =A0if((s->int_enable & FB_INT_VSYNC) && = !(s->int_status & FB_INT_VSYNC)) {
+ =A0 =A0 =A0 =A0s->= int_status |=3D FB_INT_VSYNC;
+ =A0 =A0 =A0 =A0goldfish_device_set_irq(&s->dev, 0, 1);
<= div>+ =A0 =A0}
+
+ =A0 =A0if(s->need_update) {
=
+ =A0 =A0 =A0 =A0full_update =3D 1;
+ =A0 =A0 =A0 =A0if(s-&g= t;need_int) {
+ =A0 =A0 =A0 =A0 =A0 =A0s->int_status |=3D FB_I= NT_BASE_UPDATE_DONE;
+ =A0 =A0 =A0 =A0 =A0 =A0if(s->int_enable & FB_INT_BASE_UPDATE_= DONE)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goldfish_device_set_irq(&a= mp;s->dev, 0, 1);
+ =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 = =A0s->need_int =3D 0;
+ =A0 =A0 =A0 =A0s->need_update =3D 0= ;
+ =A0 =A0}
+
+ =A0 =A0src_line =A0=3D qemu_get_ram= _ptr( base );
+
+ =A0 =A0dst_line =A0=3D s->ds->s= urface->data;
+ =A0 =A0pitch =A0 =A0 =3D s->ds->surface-= >linesize;
+ =A0 =A0width =A0 =A0 =3D s->ds->surface->= ;width;
+ =A0 =A0height =A0 =A0=3D s->ds->surface->height;
= +
+ =A0 =A0FbUpdateState =A0fbs;
+ =A0 =A0FbUpdateRect = =A0 rect;
+
+ =A0 =A0fbs.width =A0 =A0 =A0=3D width;
+ =A0 =A0fbs.height =A0 =A0 =3D height;
+ =A0 =A0fbs.dst_pixels =3D dst_line;
+ =A0 =A0fbs.dst_pitch= =A0=3D pitch;
+ =A0 =A0fbs.dst_format =3D &s->ds->surf= ace->pf;
+ =A0 =A0fbs.bytes_per_pixel =3D goldfish_fb_get_byte= s_per_pixel(s);
+
+ =A0 =A0fbs.src_pixels =3D src_line;
+ =A0 =A0//fbs.= src_pitch =A0=3D width*s->ds->surface->pf.bytes_per_pixel;
+ =A0 =A0/* the kernel only works with RGB 565 at this time */
+ =A0 =A0PixelFormat rgb_565_pf =3D qemu_default_pixelformat(16);
+ =A0 =A0fbs.src_pitch =A0=3D width * rgb_565_pf.bytes_per_pixel;
+ =A0 =A0fbs.src_format =3D &rgb_565_pf;
+
+<= /div>
+#if STATS
+ =A0 =A0if (full_update)
+ =A0 = =A0 =A0 =A0stats_full_updates +=3D 1;
+ =A0 =A0if (++stats_counter =3D=3D 120) {
+ =A0 =A0 =A0 =A0= stats_total =A0 =A0 =A0 =A0 =A0 =A0 =A0 +=3D stats_counter;
+ =A0= =A0 =A0 =A0stats_total_full_updates =A0+=3D stats_full_updates;
= +
+ =A0 =A0 =A0 =A0printf( "full update stats: =A0peak %.2f = %% =A0total %.2f %%\n",
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0stats_full_updates*100.0/stats_counte= r,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0stats_total_full_updates*100.= 0/stats_total );
+
+ =A0 =A0 =A0 =A0stats_counter =A0 = =A0 =A0=3D 0;
+ =A0 =A0 =A0 =A0stats_full_updates =3D 0;
+ =A0 =A0}
+#endif /* STATS */
+
+ =A0 = =A0if (s->blank)
+ =A0 =A0{
+ =A0 =A0 =A0 =A0memset(= dst_line, 0, height*pitch );
+ =A0 =A0 =A0 =A0rect.xmin =3D 0;
+ =A0 =A0 =A0 =A0rect.ymin =3D 0;
+ =A0 =A0 =A0 =A0rect.xmax =3D width-1;
+ =A0 =A0 =A0 =A0rec= t.ymax =3D height-1;
+ =A0 =A0}
+ =A0 =A0else
+ =A0 =A0{
+ =A0 =A0 =A0 =A0if (full_update) { /* don't use = dirty-bits optimization */
+ =A0 =A0 =A0 =A0 =A0 =A0base =3D 0;
+ =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0if (compute_fb_update_rect_linear(&fbs, base, &re= ct) =3D=3D 0) {
+ =A0 =A0 =A0 =A0 =A0 =A0return;
+ =A0 = =A0 =A0 =A0}
+ =A0 =A0}
+
+ =A0 =A0rect.xmax +=3D 1;
+ =A0 =A0rect.ymax +=3D 1;
+= #if 0
+ =A0 =A0printf("goldfish_fb_update_display (y:%d,h:%d= ,x=3D%d,w=3D%d)\n",
+ =A0 =A0 =A0 =A0 =A0 rect.ymin, rect.ym= ax-rect.ymin, rect.xmin, rect.xmax-rect.xmin);
+#endif
+
+ =A0 =A0dpy_update(s->ds, rect.xmin,= rect.ymin, rect.xmax-rect.xmin, rect.ymax-rect.ymin);
+}
+
+static void goldfish_fb_invalidate_display(void * opaque)
+{
+ =A0 =A0// is this called?
+ =A0 =A0GoldfishFB= Device *s =3D (GoldfishFBDevice *)opaque;
+ =A0 =A0s->need_upd= ate =3D 1;
+}
+
+static uint32_t goldfish_fb_= read(void *opaque, target_phys_addr_t offset)
+{
+ =A0 =A0uint32_t ret;
+ =A0 =A0GoldfishFBDevic= e *s =3D (GoldfishFBDevice *)opaque;
+
+ =A0 =A0switch(= offset) {
+ =A0 =A0 =A0 =A0case FB_GET_WIDTH:
+ =A0 =A0= =A0 =A0 =A0 =A0ret =3D ds_get_width(s->ds);
+ =A0 =A0 =A0 =A0 =A0 =A0//printf("FB_GET_WIDTH =3D> %d\n"= ;, ret);
+ =A0 =A0 =A0 =A0 =A0 =A0return ret;
+
+ =A0 =A0 =A0 =A0case FB_GET_HEIGHT:
+ =A0 =A0 =A0 =A0 =A0 =A0= ret =3D ds_get_height(s->ds);
+ =A0 =A0 =A0 =A0 =A0 =A0//printf( "FB_GET_HEIGHT =3D %d\n", ret)= ;
+ =A0 =A0 =A0 =A0 =A0 =A0return ret;
+
+ =A0 =A0 = =A0 =A0case FB_INT_STATUS:
+ =A0 =A0 =A0 =A0 =A0 =A0ret =3D s->= ;int_status & s->int_enable;
+ =A0 =A0 =A0 =A0 =A0 =A0if(r= et) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s->int_status &=3D = ~ret;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goldfish_device_set_irq(&s->de= v, 0, 0);
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 = =A0 =A0return ret;
+
+ =A0 =A0 =A0 =A0case FB_GET_PHYS_= WIDTH:
+ =A0 =A0 =A0 =A0 =A0 =A0ret =3D pixels_to_mm( ds_get_widt= h(s->ds), s->dpi );
+ =A0 =A0 =A0 =A0 =A0 =A0//printf( "FB_GET_PHYS_WIDTH =3D> %d\= n", ret );
+ =A0 =A0 =A0 =A0 =A0 =A0return ret;
+<= /div>
+ =A0 =A0 =A0 =A0case FB_GET_PHYS_HEIGHT:
+ =A0 =A0 =A0= =A0 =A0 =A0ret =3D pixels_to_mm( ds_get_height(s->ds), s->dpi );
+ =A0 =A0 =A0 =A0 =A0 =A0//printf( "FB_GET_PHYS_HEIGHT =3D> %d= \n", ret );
+ =A0 =A0 =A0 =A0 =A0 =A0return ret;
+=
+ =A0 =A0 =A0 =A0case FB_GET_FORMAT:
+ =A0 =A0 =A0 =A0= =A0 =A0return goldfish_fb_get_pixel_format(s);
+
+ =A0 =A0 =A0 =A0default:
+ =A0 =A0 =A0 =A0 =A0 = =A0cpu_abort (cpu_single_env, "goldfish_fb_read: Bad offset %x\n"= , offset);
+ =A0 =A0 =A0 =A0 =A0 =A0return 0;
+ =A0 =A0= }
+}
+
+static void goldfish_fb_write(void *opaque, target_phys_addr_t offset= ,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0uint32_t val)<= /div>
+{
+ =A0 =A0GoldfishFBDevice *s =3D (GoldfishFBDevice *= )opaque;
+
+ =A0 =A0switch(offset) {
+ =A0 =A0 =A0 =A0case FB_INT_ENABL= E:
+ =A0 =A0 =A0 =A0 =A0 =A0s->int_enable =3D val;
+= =A0 =A0 =A0 =A0 =A0 =A0goldfish_device_set_irq(&s->dev, 0, (s->i= nt_status & s->int_enable));
+ =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0case FB_SET= _BASE: {
+ =A0 =A0 =A0 =A0 =A0 =A0int need_resize =3D !s->base= _valid;
+ =A0 =A0 =A0 =A0 =A0 =A0s->fb_base =3D val;
+ =A0 =A0 =A0 =A0 =A0 =A0s->int_status &=3D ~FB_INT_BASE_UPDATE_DON= E;
+ =A0 =A0 =A0 =A0 =A0 =A0s->need_update =3D 1;
+ =A0 =A0 = =A0 =A0 =A0 =A0s->need_int =3D 1;
+ =A0 =A0 =A0 =A0 =A0 =A0s-&= gt;base_valid =3D 1;
+ =A0 =A0 =A0 =A0 =A0 =A0if(s->set_rotati= on !=3D s->rotation) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0//prin= tf("FB_SET_BASE: rotation : %d =3D> %d\n", s->rotation, s-&= gt;set_rotation);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s->rotation =3D s->set_rotation= ;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0need_resize =3D 1;
+= =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0goldfish_devic= e_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ =A0 =A0 =A0 =A0 =A0 =A0if (need_resize) {
+ =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0//printf("FB_SET_BASE: need resize (rotation=3D%d)\= n", s->rotation );
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dpy_r= esize(s->ds);
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0} break;
+ =A0 =A0 =A0 =A0case FB_S= ET_ROTATION:
+ =A0 =A0 =A0 =A0 =A0 =A0//printf( "FB_SET_ROTA= TION %d\n", val);
+ =A0 =A0 =A0 =A0 =A0 =A0s->set_rotatio= n =3D val;
+ =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0case FB_SET_BLANK:
+ =A0 =A0 =A0 =A0 =A0 = =A0s->blank =3D val;
+ =A0 =A0 =A0 =A0 =A0 =A0s->need_updat= e =3D 1;
+ =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 = =A0default:
+ =A0 =A0 =A0 =A0 =A0 =A0cpu_abort (cpu_single_env, &= quot;goldfish_fb_write: Bad offset %x\n", offset);
+ =A0 =A0}
+}
+
+static CPUReadMemoryFun= c *goldfish_fb_readfn[] =3D {
+ =A0 goldfish_fb_read,
+= =A0 goldfish_fb_read,
+ =A0 goldfish_fb_read
+};
=
+
+static CPUWriteMemoryFunc *goldfish_fb_writefn[] =3D {
+ = =A0 goldfish_fb_write,
+ =A0 goldfish_fb_write,
+ =A0 g= oldfish_fb_write
+};
+
+static int goldfish_f= b_init(GoldfishDevice *dev)
+{
+ =A0 =A0GoldfishFBDevice *s =3D (GoldfishFBDevice *)dev;=
+
+ =A0 =A0s->ds =3D graphic_console_init(goldfish_= fb_update_display,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 goldfish_fb_invalidate_display,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL= ,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 NULL,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 s);
+
+ =A0 =A0s->dpi =3D 165; =A0/* XXX= : Find better way to get actual value ! */
+
+ =A0 =A0/* IMPORTANT: DO NOT COMPUTE s->pixel_format a= nd s->bytes_per_pixel
+ =A0 =A0 * here because the display sur= face is going to change later.
+ =A0 =A0 */
+ =A0 =A0s-= >bytes_per_pixel =3D 0;
+ =A0 =A0s->pixel_format =A0 =A0=3D -1;
+
+ =A0= =A0//goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_w= ritefn, s);
+
+ =A0 =A0//register_savevm( NULL, "g= oldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION,
+ =A0 =A0// =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goldfish_fb_save, goldfish= _fb_load, s);
+
+ =A0 =A0return 0;
+}
+
+DeviceState *goldfish_fb_create(GoldfishBus *gbus, int id)<= /div>
+{
+ =A0 =A0DeviceState *dev;
+ =A0 =A0char *name =3D (char *)"= goldfish_fb";
+
+ =A0 =A0dev =3D qdev_create(&= gbus->bus, name);
+ =A0 =A0qdev_prop_set_string(dev, "nam= e", name);
+ =A0 =A0qdev_prop_set_uint32(dev, "id", id);
+ = =A0 =A0qdev_init_nofail(dev);
+
+ =A0 =A0return dev;
+}
+
+static GoldfishDeviceInfo goldfish_fb_inf= o =3D {
+ =A0 =A0.init =3D goldfish_fb_init,
+ =A0 =A0.readfn =3D go= ldfish_fb_readfn,
+ =A0 =A0.writefn =3D goldfish_fb_writefn,
+ =A0 =A0.qdev.size =A0=3D sizeof(GoldfishFBDevice),
+ =A0 =A0.qd= ev.props =3D (Property[]) {
+ =A0 =A0 =A0 =A0DEFINE_PROP_UINT32(&= quot;base", GoldfishDevice, base, 0),
+ =A0 =A0 =A0 =A0DEFIN= E_PROP_UINT32("id", GoldfishDevice, id, -1),
+ =A0 =A0 =A0 =A0DEFINE_PROP_UINT32("size", GoldfishDevice, = size, 0x1000),
+ =A0 =A0 =A0 =A0DEFINE_PROP_UINT32("irq"= ;, GoldfishDevice, irq, 0),
+ =A0 =A0 =A0 =A0DEFINE_PROP_UINT32(&= quot;irq_count", GoldfishDevice, irq_count, 1),
+ =A0 =A0 =A0 =A0DEFINE_PROP_STRING("name", GoldfishDevice, = name),
+ =A0 =A0 =A0 =A0DEFINE_PROP_END_OF_LIST(),
+ = =A0 =A0},
+};
+
+static void goldfish_fb_regi= ster(void)
+{
+ =A0 =A0goldfish_bus_register_withprop(&goldfish_fb_info)= ;
+}
+device_init(goldfish_fb_register);
--= =A0
1.7.4.1

--00248c7119dd0ae82104ab14da30--