--- /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;
+}