symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/fb_render_engine.c
changeset 1 2fb8b9db1c86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/fb_render_engine.c	Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,627 @@
+/*
+ *  Render Engine for framebuffer devices
+ *
+ *  Copyright (c) 2008 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "hw.h"
+//#include "console.h"
+#include "gui.h"
+#include "fb_render_engine.h"
+#include "pixel_ops.h"
+
+typedef void (*row_draw_fn)(uint32_t *, uint8_t *, const uint8_t *, int, int);
+
+enum fb_dest_bpp_mode
+{
+    BPP_DEST_8,
+    BPP_DEST_15,
+    BPP_DEST_16,
+    BPP_DEST_24,
+    BPP_DEST_32
+};
+
+struct render_data_t {
+    int base_is_in_target;
+    union {
+        void* base_host;
+        target_phys_addr_t base_target;
+    };
+    uint8_t *dest;
+    uint32_t cols;
+    uint32_t rows;
+    uint32_t row_pitch;
+    /* The following attributes refer to the guest side.
+       They should be renamed once they are also variable
+       at the host side.
+    */
+    enum fb_pixel_order pixel_order;
+    enum fb_byte_order  byte_order;
+    enum fb_color_order color_order;
+    enum fb_src_bpp_mode  src_bpp_mode;
+
+    enum fb_dest_bpp_mode dest_bpp_mode;
+    /* pending:
+        pixel_order, byte_order, and color_order, for the dest (host).
+    */
+    enum fb_rotation orientation;
+    uint32_t blank : 1;
+    uint32_t need_internal_update : 1;
+    uint32_t raw_palette[256];
+
+    /* ====== cached internal data ===== */
+    uint32_t inter_src_row_gap;
+    uint32_t bytes_per_src_row; /* Does not include padding.  */
+    row_draw_fn fn;
+    /* rotation info */
+    uint32_t dest_start_offset;
+    uint32_t bytes_per_dest_row;
+    int      dest_row_step;  /* in bytes */
+    int      dest_col_step;  /* in bytes */
+    int      swap_width_height;
+    /* color info */
+    uint32_t palette[256];
+
+};
+
+
+#define NOT_ASSIGNED -1
+
+#include "fb_render_def.h"
+#include "fb_render_decl.h"
+
+/* getters */
+uint32_t get_cols(const render_data *rd)
+{
+    return rd->cols;
+}
+
+uint32_t get_rows(const render_data *rd)
+{
+    return rd->rows;
+}
+
+uint32_t get_screen_width(const render_data *rd)
+{
+    return (!rd->swap_width_height) ? rd->cols : rd->rows;
+}
+
+uint32_t get_screen_height(const render_data *rd)
+{
+    return (!rd->swap_width_height) ? rd->rows : rd->cols;
+}
+
+enum fb_rotation get_orientation(const render_data *rd)
+{
+    return rd->orientation;
+}
+
+void* get_fb_base_in_host(const render_data *rd)
+{
+    return rd->base_is_in_target ? 0 : rd->base_host;
+}
+
+target_phys_addr_t get_fb_base_in_target(const render_data *rd)
+{
+    return rd->base_is_in_target ? rd->base_target : 0;
+}
+
+uint32_t get_blank_mode(const render_data *rd)
+{
+    return rd->blank;
+}
+
+enum fb_color_order get_color_order(const render_data *rd)
+{
+    return rd->color_order;
+}
+
+enum fb_byte_order get_byte_order(const render_data *rd)
+{
+    return rd->byte_order;
+}
+
+enum fb_pixel_order get_pixel_order(const render_data *rd)
+{
+    return rd->pixel_order;
+}
+
+enum fb_src_bpp_mode get_src_bpp(const render_data *rd)
+{
+    return rd->src_bpp_mode;
+}
+
+uint32_t get_row_pitch(const render_data *rd)
+{
+    return rd->row_pitch;
+}
+
+uint32_t get_palette_value(const render_data *rd, uint32_t n)
+{
+    return rd->raw_palette[n];
+}
+
+
+/* setters */
+void set_cols(render_data *rd, uint32_t cols)
+{
+    rd->cols = cols; rd->need_internal_update = 1;
+}
+
+void set_rows(render_data *rd, uint32_t rows)
+{
+    rd->rows = rows; rd->need_internal_update = 1;
+}
+
+void set_orientation(render_data *rd, enum fb_rotation rotation)
+{
+    rd->orientation = rotation; rd->need_internal_update = 1;
+}
+
+void set_fb_base_from_host(render_data *rd, void* base)
+{
+    rd->base_is_in_target = 0;
+    rd->base_host = base; rd->need_internal_update = 1;
+}
+
+void set_fb_base_from_target(render_data *rd, target_phys_addr_t base)
+{
+    rd->base_is_in_target = 1;
+    /* ensure alignment */
+    rd->base_target = (base & (~3)); rd->need_internal_update = 1;
+}
+
+void set_blank_mode(render_data *rd, int on_off)
+{
+    rd->blank = on_off; rd->need_internal_update = 1;
+}
+
+void set_pixel_order(render_data *rd, enum fb_pixel_order pixel_order)
+{
+    rd->pixel_order = pixel_order; rd->need_internal_update = 1;
+}
+
+void set_byte_order(render_data *rd, enum fb_byte_order byte_order)
+{
+    rd->byte_order = byte_order; rd->need_internal_update = 1;
+}
+
+void set_color_order(render_data *rd, enum fb_color_order color_order)
+{
+    rd->color_order = color_order; rd->need_internal_update = 1;
+}
+
+void set_src_bpp(render_data *rd, enum fb_src_bpp_mode src_bpp_mode)
+{
+    rd->src_bpp_mode = src_bpp_mode; rd->need_internal_update = 1;
+}
+
+void set_row_pitch(render_data *rd, uint32_t pitch)
+{
+    rd->row_pitch = pitch & ~3; rd->need_internal_update = 1;
+}
+
+static void set_dest_bpp(render_data *rd, enum fb_dest_bpp_mode dest_bpp_mode)
+{
+    rd->dest_bpp_mode = dest_bpp_mode; rd->need_internal_update = 1;
+}
+
+static void set_dest_bpp_from_ds(render_data *rd, const DisplayState *ds)
+{
+    enum fb_dest_bpp_mode new_dest_bpp_mode;
+
+    switch (ds_get_bits_per_pixel(ds)) {
+    case  8: new_dest_bpp_mode = BPP_DEST_8;  break;
+    case 15: new_dest_bpp_mode = BPP_DEST_15; break;
+    case 16: new_dest_bpp_mode = BPP_DEST_16; break;
+    case 24: new_dest_bpp_mode = BPP_DEST_24; break;
+    case 32: new_dest_bpp_mode = BPP_DEST_32; break;
+    default:
+        fprintf(stderr, "fb_render_engine: Bad color depth\n");
+        exit(1);
+    }
+
+    if (rd->dest_bpp_mode != new_dest_bpp_mode)
+        set_dest_bpp(rd, new_dest_bpp_mode);
+}
+
+static void set_dest_data_from_ds(render_data *rd, const DisplayState *ds)
+{
+    set_dest_bpp_from_ds(rd, ds);
+
+    /* calculate row size */
+    rd->bytes_per_dest_row = ds_get_linesize(ds);
+}
+
+/* this function rounds down odd widths */
+static uint32_t calc_bytes_per_src_row(enum fb_src_bpp_mode bpp, uint32_t cols)
+{
+    uint32_t bytes_per_row = cols;
+
+    switch (bpp) {
+    case BPP_SRC_1:
+        bytes_per_row >>= 3;
+        break;
+
+    case BPP_SRC_2:
+        bytes_per_row >>= 2;
+        break;
+
+    case BPP_SRC_4:
+        bytes_per_row >>= 1;
+        break;
+
+    case BPP_SRC_8:
+        break;
+
+    case BPP_SRC_15:
+    case BPP_SRC_16:
+        bytes_per_row <<= 1;
+        break;
+
+    case BPP_SRC_24:
+        bytes_per_row *= 3;
+        break;
+
+    case BPP_SRC_32:
+        bytes_per_row <<= 2;
+        break;
+    }
+
+    if (bpp != BPP_SRC_24 && (bytes_per_row % 4) != 0) {
+        fprintf(stderr, "Warning: setting an invalid width/depth combination, rounding down.\n");
+        bytes_per_row &= ~3;
+    }
+
+    return bytes_per_row;
+}
+
+static uint32_t calc_bytes_per_dest_row(enum fb_dest_bpp_mode bpp, uint32_t cols)
+{
+    uint32_t bytes_per_row = cols;
+
+    switch (bpp) {
+    case BPP_DEST_8:
+        break;
+    case BPP_DEST_15:
+    case BPP_DEST_16:
+        bytes_per_row <<= 1;
+        break;
+    case BPP_DEST_24:
+        bytes_per_row *= 3;
+        break;
+    case BPP_DEST_32:
+        bytes_per_row <<= 2;
+        break;
+    }
+
+    return bytes_per_row;
+}
+
+static row_draw_fn get_draw_fn(const render_data * rd)
+{
+    return fb_draw_fn[rd->dest_bpp_mode][rd->color_order][rd->byte_order][rd->pixel_order][rd->src_bpp_mode];
+}
+
+inline static void* calc_src_row_address_host(const render_data * rd, uint32_t row)
+{
+    return (void*)((char*)(rd->base_host) + row * (rd->bytes_per_src_row + rd->inter_src_row_gap));
+}
+
+inline static ram_addr_t calc_src_row_address_target(const render_data * rd, uint32_t row)
+{
+    target_phys_addr_t phys;
+    phys = rd->base_target + row * (rd->bytes_per_src_row + rd->inter_src_row_gap);
+    return get_ram_offset_phys(phys);
+}
+
+inline static uint8_t *calc_dest_row_address(const render_data * rd, int row)
+{
+    return rd->dest + rd->dest_start_offset + row * rd->dest_col_step;
+}
+
+static int is_dirty_row(const render_data * rd, uint32_t row)
+{
+    int dirty;
+    uint32_t addr;
+    uint32_t end;
+
+    addr = calc_src_row_address_target(rd, row);
+    end = (addr + rd->bytes_per_src_row - 1) & TARGET_PAGE_MASK;
+    addr &= TARGET_PAGE_MASK;
+
+    /* Iterate over all the pages belonging to this row */
+
+    do {
+        dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
+        addr += TARGET_PAGE_SIZE;
+    } while (!dirty && addr <= end);
+
+    return dirty;
+}
+
+static void draw_blank_row(uint8_t *dest, uint32_t bytes)
+{
+    memset(dest, 0, bytes);
+}
+
+
+static void decode_rgb_for_palette(uint32_t data, unsigned int *r, unsigned int *g, unsigned int *b)
+{
+    *r = (data >> 16) & 0xff;
+    *g = (data >> 8) & 0xff;
+    *b = data & 0xff;
+}
+
+static void update_complete_palette(render_data * rd)
+{
+    int n, i;
+    uint32_t raw;
+    unsigned int r, g, b;
+
+    switch (rd->src_bpp_mode) {
+    case BPP_SRC_1: n = 2; break;
+    case BPP_SRC_2: n = 4; break;
+    case BPP_SRC_4: n = 16; break;
+    case BPP_SRC_8: n = 256; break;
+    default: return;
+    }
+
+    for (i=0; i<n; i++) {
+        raw = rd->raw_palette[i];
+        decode_rgb_for_palette(raw, &r, &g, &b);
+        switch (rd->dest_bpp_mode) {
+        case BPP_DEST_8:
+            rd->palette[i] = rgb_to_pixel8(r, g, b);
+            break;
+        case BPP_DEST_15:
+            rd->palette[i] = rgb_to_pixel15(r, g, b);
+            break;
+        case BPP_DEST_16:
+            rd->palette[i] = rgb_to_pixel16(r, g, b);
+            break;
+        case BPP_DEST_24:
+        case BPP_DEST_32:
+            rd->palette[i] = rgb_to_pixel32(r, g, b);
+            break;
+        }
+    }
+}
+
+/* Mapping from guest (row/col) to host (x/y) coordinates.  */ 
+typedef struct {
+    int row_x;
+    int row_y;
+    int col_x;
+    int col_y;
+} rotation_data;
+
+static const rotation_data rotations[8] = {
+      { 1,  0,  0,  1},
+      { 0, -1,  1,  0},
+      {-1,  0,  0, -1},
+      { 0,  1, -1,  0},
+      { 1,  0,  0, -1},
+      { 0,  1,  1,  0},
+      {-1,  0,  0,  1},
+      { 0, -1, -1,  0},
+};
+
+static void update_rotation_data(render_data *rd)
+{
+    uint32_t bytes_per_dest_pixel;
+    const rotation_data *r;
+
+    r = &rotations[rd->orientation];
+
+    /*rd->swap_width_height = rd->orientation & 1;*/
+
+#if 0
+    TODO DFG
+    rd->bytes_per_dest_row = calc_bytes_per_dest_row(rd->dest_bpp_mode, get_screen_width(rd));
+#endif
+    bytes_per_dest_pixel = calc_bytes_per_dest_row(rd->dest_bpp_mode, get_screen_width(rd)) / get_screen_width(rd);
+
+    /* Offset the start position if we are rendering backwards.  */
+    rd->dest_start_offset = 0;
+    if (r->row_x + r->col_x < 0)
+        rd->dest_start_offset += bytes_per_dest_pixel * (get_screen_width(rd) - 1);
+        /*rd->dest_start_offset += rd->bytes_per_dest_row - bytes_per_dest_pixel;*/
+
+    if (r->row_y + r->col_y < 0)
+        rd->dest_start_offset += rd->bytes_per_dest_row * (get_screen_height(rd) - 1);
+
+    rd->dest_row_step = rd->bytes_per_dest_row * r->row_y
+                        + bytes_per_dest_pixel * r->row_x;
+    rd->dest_col_step = rd->bytes_per_dest_row * r->col_y
+                        + bytes_per_dest_pixel * r->col_x;
+}
+
+static void update_render_data(render_data *rd)
+{
+    if (rd->need_internal_update) {
+        rd->fn = get_draw_fn(rd);
+        rd->bytes_per_src_row = calc_bytes_per_src_row(rd->src_bpp_mode,
+                                                       rd->cols);
+        update_complete_palette(rd);
+        if (rd->row_pitch == 0)
+            rd->inter_src_row_gap = 0;
+        else
+            rd->inter_src_row_gap = rd->row_pitch - rd->bytes_per_src_row;
+        update_rotation_data(rd); /* updates bytes_per_dest_row too */
+        rd->need_internal_update = 0;
+    }
+}
+
+
+void set_palette_value(render_data *rd, uint32_t n, uint32_t value)
+{
+    rd->raw_palette[n] = value;
+    rd->need_internal_update = 1;
+}
+
+static void render_blank_screen(render_data * rdata)
+{
+    int i;
+    uint8_t* addr = rdata->dest;
+    const uint32_t rows = get_screen_height(rdata);
+
+    for (i = 0; i < rows; i++) {
+        draw_blank_row(addr, rdata->bytes_per_dest_row);
+        addr += rdata->bytes_per_dest_row;
+    }
+}
+
+static void render_from_host(DisplayState *ds, const render_data *rdata)
+{
+    int i;
+
+    for (i = 0; i < rdata->rows; i++) {
+        rdata->fn(rdata->palette, 
+                  calc_dest_row_address(rdata, i),
+                  /*(uint8_t *)*/calc_src_row_address_host(rdata, i),
+                  rdata->cols, 
+                  rdata->dest_row_step);
+    }
+
+    if (!rdata->swap_width_height)
+        dpy_update(ds, 0, 0, rdata->cols, rdata->rows);
+    else
+        dpy_update(ds, 0, 0, rdata->rows, rdata->cols);
+
+}
+
+static void render_from_target(DisplayState *ds, const render_data *rdata, int full_update)
+{
+    int first_dirty_row = NOT_ASSIGNED, last_dirty_row = 0;
+    int i;
+
+    for (i = 0; i < rdata->rows; i++) {
+        if (full_update || is_dirty_row(rdata, i)) {
+            /* FIXME: This is broken if it spans multiple RAM regions.  */
+            rdata->fn(rdata->palette, 
+                      calc_dest_row_address(rdata, i),
+                      host_ram_addr(calc_src_row_address_target(rdata, i)),
+                      rdata->cols, 
+                      rdata->dest_row_step);
+
+            if (first_dirty_row == NOT_ASSIGNED)
+                first_dirty_row = i;
+            last_dirty_row = i;
+        }
+    }
+
+    if (first_dirty_row != NOT_ASSIGNED) {
+        cpu_physical_memory_reset_dirty(
+            calc_src_row_address_target(rdata, first_dirty_row), /* first row byte */
+            calc_src_row_address_target(rdata, last_dirty_row + 1) - 1, /* last row byte */
+            VGA_DIRTY_FLAG);
+
+        if (!rdata->swap_width_height)
+            dpy_update(ds, 0, first_dirty_row, rdata->cols, last_dirty_row - first_dirty_row + 1);
+        else
+            dpy_update(ds, first_dirty_row, 0, last_dirty_row - first_dirty_row + 1, rdata->cols);
+    }
+}
+
+static int prepare_ds_for_rendering(DisplayState *ds, render_data *rdata)
+{
+    rdata->swap_width_height = rdata->orientation & 1;
+
+    if (ds_get_width(ds) == get_screen_width(rdata) && 
+        ds_get_height(ds) == get_screen_height(rdata))
+        return 1;
+    else
+        return gui_resize_vt(ds, get_screen_width(rdata), get_screen_height(rdata));
+}
+
+void render(DisplayState *ds, render_data * rdata, int full_update)
+{
+    if (prepare_ds_for_rendering(ds, rdata)) {
+
+        rdata->dest = ds_get_data(ds);
+        
+        set_dest_data_from_ds(rdata, ds);
+
+        rdata->need_internal_update |= full_update;
+        update_render_data(rdata);
+
+        if (rdata->blank) {
+            render_blank_screen(rdata);
+        } else {
+            if (rdata->base_is_in_target)
+                render_from_target(ds, rdata, full_update);
+            else
+                render_from_host(ds, rdata);
+        }
+    }
+}
+
+render_data *create_render_data()
+{
+   render_data *rdata = qemu_mallocz(sizeof(render_data));
+
+   /* set some defaults */
+
+   return rdata;
+}
+
+void destroy_render_data(render_data *rd)
+{
+    qemu_free(rd);
+}
+
+void qemu_put_render_data(QEMUFile *f, const render_data *s)
+{
+    int i;
+
+    qemu_put_be32(f, s->base_is_in_target);
+    if (s->base_is_in_target)
+        qemu_put_be64(f, s->base_target);
+    qemu_put_be32(f, s->cols);
+    qemu_put_be32(f, s->rows);
+    qemu_put_be32(f, s->row_pitch);
+    qemu_put_be32(f, s->pixel_order);
+    qemu_put_be32(f, s->byte_order);
+    qemu_put_be32(f, s->color_order);
+    qemu_put_be32(f, s->src_bpp_mode);
+    qemu_put_be32(f, s->orientation);
+    qemu_put_be32(f, s->blank);
+    for (i = 0; i < 256; i++)
+        qemu_put_be32(f, s->raw_palette[i]);
+}
+
+void qemu_get_render_data(QEMUFile *f, render_data *s)
+{
+    int i;
+
+    s->base_is_in_target = qemu_get_be32(f);
+    if (s->base_is_in_target)
+        s->base_target = qemu_get_be64(f);
+    s->cols = qemu_get_be32(f);
+    s->rows = qemu_get_be32(f);
+    s->row_pitch = qemu_get_be32(f);
+    s->pixel_order = qemu_get_be32(f);
+    s->byte_order = qemu_get_be32(f);
+    s->color_order = qemu_get_be32(f);
+    s->src_bpp_mode = qemu_get_be32(f);
+    s->orientation = qemu_get_be32(f);
+    s->blank = qemu_get_be32(f);
+    for (i = 0; i < 256; i++)
+        s->raw_palette[i] = qemu_get_be32(f);
+    s->need_internal_update = 1;
+}