From f721e3ac031f892af46f255a47d7f54a91317b30 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 18:28:35 -0800 Subject: auto import from //depot/cupcake/@135843 --- hw/goldfish_fb.c | 405 ------------------------------------------------------- 1 file changed, 405 deletions(-) delete mode 100644 hw/goldfish_fb.c (limited to 'hw/goldfish_fb.c') diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c deleted file mode 100644 index 71cede2..0000000 --- a/hw/goldfish_fb.c +++ /dev/null @@ -1,405 +0,0 @@ -/* 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 "qemu_file.h" -#include "android/android.h" -#include "goldfish_device.h" -#include "framebuffer.h" - -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_INT_VSYNC = 1U << 0, - FB_INT_BASE_UPDATE_DONE = 1U << 1 -}; - -struct goldfish_fb_state { - struct goldfish_device dev; - QFrameBuffer* qfbuff; - 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 */ -}; - -#define GOLDFISH_FB_SAVE_VERSION 1 - -static void goldfish_fb_save(QEMUFile* f, void* opaque) -{ - struct goldfish_fb_state* s = opaque; - - QFrameBuffer* q = s->qfbuff; - - qemu_put_be32(f, q->width); - qemu_put_be32(f, q->height); - qemu_put_be32(f, q->pitch); - qemu_put_byte(f, q->rotation); - - qemu_put_be32(f, s->fb_base); - qemu_put_byte(f, s->base_valid); - qemu_put_byte(f, s->need_update); - qemu_put_byte(f, s->need_int); - qemu_put_byte(f, s->set_rotation); - qemu_put_byte(f, s->blank); - qemu_put_be32(f, s->int_status); - qemu_put_be32(f, s->int_enable); - qemu_put_be32(f, s->rotation); -} - -static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id) -{ - struct goldfish_fb_state* s = opaque; - - QFrameBuffer* q = s->qfbuff; - int ret = -1; - int ds_w, ds_h, ds_pitch, ds_rot; - - if (version_id != GOLDFISH_FB_SAVE_VERSION) - goto Exit; - - ds_w = qemu_get_be32(f); - ds_h = qemu_get_be32(f); - ds_pitch = qemu_get_be32(f); - ds_rot = qemu_get_byte(f); - - if (q->width != ds_w || - q->height != ds_h || - q->pitch != ds_pitch || - q->rotation != ds_rot ) - { - /* XXX: We should be able to force a resize/rotation from here ? */ - fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__); - goto Exit; - } - - s->fb_base = qemu_get_be32(f); - s->base_valid = qemu_get_byte(f); - s->need_update = qemu_get_byte(f); - s->need_int = qemu_get_byte(f); - s->set_rotation = qemu_get_byte(f); - s->blank = qemu_get_byte(f); - s->int_status = qemu_get_be32(f); - s->int_enable = qemu_get_be32(f); - s->rotation = qemu_get_be32(f); - - /* force a refresh */ - s->need_update = 1; - - ret = 0; -Exit: - return ret; -} - - -#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 - -static void goldfish_fb_update_display(void *opaque) -{ - struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; - uint32_t addr; - uint32_t base; - - uint8_t* dst_line; - uint8_t* src_line; - int y_first, y_last = 0; - 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); - } - - y_first = -1; - addr = base; - 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 = phys_ram_base + base; - dst_line = s->qfbuff->pixels; - pitch = s->qfbuff->pitch; - width = s->qfbuff->width; - height = s->qfbuff->height; - -#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 ); - y_first = 0; - y_last = height-1; - } - else if (full_update) - { - int yy; - - for (yy = 0; yy < height; yy++, dst_line += pitch, src_line += width*2) - { - uint16_t* src = (uint16_t*) src_line; - uint16_t* dst = (uint16_t*) dst_line; - int nn; - - for (nn = 0; nn < width; nn++) { - unsigned spix = src[nn]; - unsigned dpix = dst[nn]; -#if WORDS_BIGENDIAN - spix = ((spix << 8) | (spix >> 8)) & 0xffff; -#else - if (spix != dpix) - break; -#endif - } - - if (nn == width) - continue; - -#if WORDS_BIGENDIAN - for ( ; nn < width; nn++ ) { - unsigned spix = src[nn]; - dst[nn] = (uint16_t)((spix << 8) | (spix >> 8)); - } -#else - memcpy( dst+nn, src+nn, (width-nn)*2 ); -#endif - - y_first = (y_first < 0) ? yy : y_first; - y_last = yy; - } - } - else /* not a full update, should not happen very often with Android */ - { - int yy; - - for (yy = 0; yy < height; yy++, dst_line += pitch, src_line += width*2) - { - uint16_t* src = (uint16_t*) src_line; - uint16_t* dst = (uint16_t*) dst_line; - int len = width*2; -#if WORDS_BIGENDIAN - int nn; -#endif - int dirty = 0; - - while (len > 0) { - int len2 = TARGET_PAGE_SIZE - (addr & (TARGET_PAGE_SIZE-1)); - - if (len2 > len) - len2 = len; - - dirty |= cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG); - addr += len2; - len -= len2; - } - - if (!dirty) - continue; - -#if WORDS_BIGENDIAN - for (nn = 0; nn < width; nn++ ) { - unsigned spix = src[nn]; - dst[nn] = (uint16_t)((spix << 8) | (spix >> 8)); - } -#else - memcpy( dst, src, width*2 ); -#endif - - y_first = (y_first < 0) ? yy : y_first; - y_last = yy; - } - } - - if (y_first < 0) - return; - - y_last += 1; - //printf("goldfish_fb_update_display %d %d, base %x\n", first, last, base); - - cpu_physical_memory_reset_dirty(base + y_first * width * 2, - base + y_last * width * 2, - VGA_DIRTY_FLAG); - - qframebuffer_update( s->qfbuff, 0, y_first, width, y_last-y_first ); -} - -static void goldfish_fb_invalidate_display(void * opaque) -{ - // is this called? - struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; - s->need_update = 1; -} - -static void goldfish_fb_detach_display(void* opaque) -{ - struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; - s->qfbuff = NULL; -} - -static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset) -{ - uint32_t ret; - struct goldfish_fb_state *s = opaque; - offset -= s->dev.base; - switch(offset) { - case FB_GET_WIDTH: - ret = s->qfbuff->width; - //printf("FB_GET_WIDTH => %d\n", ret); - return ret; - - case FB_GET_HEIGHT: - ret = s->qfbuff->height; - //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 = s->qfbuff->phys_width_mm; - //printf( "FB_GET_PHYS_WIDTH => %d\n", ret ); - return ret; - - case FB_GET_PHYS_HEIGHT: - ret = s->qfbuff->phys_height_mm; - //printf( "FB_GET_PHYS_HEIGHT => %d\n", ret ); - return ret; - - 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) -{ - struct goldfish_fb_state *s = opaque; - offset -= s->dev.base; - 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 ); - qframebuffer_rotate( s->qfbuff, s->rotation ); - } - } 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 -}; - -void goldfish_fb_init(DisplayState *ds, int id) -{ - struct goldfish_fb_state *s; - - s = (struct goldfish_fb_state *)qemu_mallocz(sizeof(*s)); - s->dev.name = "goldfish_fb"; - s->dev.id = id; - s->dev.size = 0x1000; - s->dev.irq_count = 1; - - s->qfbuff = qframebuffer_fifo_get(); - qframebuffer_set_producer( s->qfbuff, s, - goldfish_fb_update_display, - goldfish_fb_invalidate_display, - goldfish_fb_detach_display ); - - goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s); - - register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION, - goldfish_fb_save, goldfish_fb_load, s); -} - -- cgit v1.1