* [Qemu-devel] [6965] Implement and use shared memory framebuffer device rendering reoutine.
@ 2009-04-01 12:28 Paul Brook
2009-04-02 20:52 ` andrzej zaborowski
0 siblings, 1 reply; 3+ messages in thread
From: Paul Brook @ 2009-04-01 12:28 UTC (permalink / raw)
To: qemu-devel
Revision: 6965
http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=6965
Author: pbrook
Date: 2009-04-01 12:27:59 +0000 (Wed, 01 Apr 2009)
Log Message:
-----------
Implement and use shared memory framebuffer device rendering reoutine.
Use DMA mapping API.
Signed-off-by: Paul Brook <paul@codesourcery.com>
Modified Paths:
--------------
trunk/Makefile.target
trunk/hw/omap.h
trunk/hw/omap_lcd_template.h
trunk/hw/omap_lcdc.c
trunk/hw/pl110.c
trunk/hw/pl110_template.h
trunk/hw/pxa2xx_lcd.c
trunk/hw/pxa2xx_template.h
Added Paths:
-----------
trunk/hw/framebuffer.c
trunk/hw/framebuffer.h
Modified: trunk/Makefile.target
===================================================================
--- trunk/Makefile.target 2009-04-01 11:43:02 UTC (rev 6964)
+++ trunk/Makefile.target 2009-04-01 12:27:59 UTC (rev 6965)
@@ -672,6 +672,7 @@
OBJS+= tsc2005.o bt-hci-csr.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
+OBJS+= framebuffer.o
CPPFLAGS += -DHAS_AUDIO
endif
ifeq ($(TARGET_BASE_ARCH), sh4)
Added: trunk/hw/framebuffer.c
===================================================================
--- trunk/hw/framebuffer.c (rev 0)
+++ trunk/hw/framebuffer.c 2009-04-01 12:27:59 UTC (rev 6965)
@@ -0,0 +1,119 @@
+/*
+ * Framebuffer device helper routines
+ *
+ * Copyright (c) 2009 CodeSourcery
+ * Written by Paul Brook <paul@codesourcery.com>
+ *
+ * This code is licensed under the GNU GPLv2.
+ */
+
+/* TODO:
+ - Do something similar for framebuffers with local ram
+ - Handle rotation here instead of hacking dest_pitch
+ - Use common pixel conversion routines instead of per-device drawfn
+ - Remove all DisplayState knowledge from devices.
+ */
+
+#include "hw.h"
+#include "console.h"
+#include "framebuffer.h"
+#include "kvm.h"
+
+/* Render an image from a shared memory framebuffer. */
+
+void framebuffer_update_display(
+ DisplayState *ds,
+ target_phys_addr_t base,
+ int cols, /* Width in pixels. */
+ int rows, /* Leight in pixels. */
+ int src_width, /* Length of source line, in bytes. */
+ int dest_row_pitch, /* Bytes between adjacent horizontal output pixels. */
+ int dest_col_pitch, /* Bytes between adjacent vertical output pixels. */
+ int invalidate, /* nonzero to redraw the whole image. */
+ drawfn fn,
+ void *opaque,
+ int *first_row, /* Input and output. */
+ int *last_row /* Output only */)
+{
+ target_phys_addr_t src_len;
+ uint8_t *dest;
+ uint8_t *src;
+ uint8_t *src_base;
+ int first, last = 0;
+ int dirty;
+ int i;
+ ram_addr_t addr;
+ ram_addr_t pd;
+ ram_addr_t pd2;
+
+ i = *first_row;
+ *first_row = -1;
+ src_len = src_width * rows;
+
+ if (kvm_enabled()) {
+ kvm_physical_sync_dirty_bitmap(base, src_len);
+ }
+ pd = cpu_get_physical_page_desc(base);
+ pd2 = cpu_get_physical_page_desc(base + src_len - 1);
+ /* We should reall check that this is a continuous ram region.
+ Instead we just check that the first and last pages are
+ both ram, and the right distance apart. */
+ if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM
+ || (pd2 & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+ return;
+ }
+ pd = (pd & TARGET_PAGE_MASK) + (base & ~TARGET_PAGE_MASK);
+ if (((pd + src_len - 1) & TARGET_PAGE_MASK) != (pd2 & TARGET_PAGE_MASK)) {
+ return;
+ }
+
+ src_base = cpu_physical_memory_map(base, &src_len, 0);
+ /* If we can't map the framebuffer then bail. We could try harder,
+ but it's not really worth it as dirty flag tracking will probably
+ already have failed above. */
+ if (!src_base)
+ return;
+ if (src_len != src_width * rows) {
+ cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+ return;
+ }
+ src = src_base;
+ dest = ds_get_data(ds);
+ if (dest_col_pitch < 0)
+ dest -= dest_col_pitch * (cols - 1);
+ first = -1;
+ addr = pd;
+
+ addr += i * src_width;
+ src += i * src_width;
+ dest += i * dest_row_pitch;
+
+ for (; i < rows; i++) {
+ target_phys_addr_t dirty_offset;
+ dirty = 0;
+ dirty_offset = 0;
+ while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) {
+ dirty |= cpu_physical_memory_get_dirty(addr + dirty_offset,
+ VGA_DIRTY_FLAG);
+ dirty_offset += TARGET_PAGE_SIZE;
+ }
+
+ if (dirty || invalidate) {
+ fn(opaque, dest, src, cols, dest_col_pitch);
+ if (first == -1)
+ first = i;
+ last = i;
+ }
+ addr += src_width;
+ src += src_width;
+ dest += dest_row_pitch;
+ }
+ cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+ if (first < 0) {
+ return;
+ }
+ cpu_physical_memory_reset_dirty(pd, pd + src_len, VGA_DIRTY_FLAG);
+ *first_row = first;
+ *last_row = last;
+ return;
+}
Added: trunk/hw/framebuffer.h
===================================================================
--- trunk/hw/framebuffer.h (rev 0)
+++ trunk/hw/framebuffer.h 2009-04-01 12:27:59 UTC (rev 6965)
@@ -0,0 +1,22 @@
+#ifndef QEMU_FRAMEBUFFER_H
+#define QEMU_FRAMEBUFFER_H
+
+/* Framebuffer device helper routines. */
+
+typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int);
+
+void framebuffer_update_display(
+ DisplayState *ds,
+ target_phys_addr_t base,
+ int cols,
+ int rows,
+ int src_width,
+ int dest_row_pitch,
+ int dest_col_pitch,
+ int invalidate,
+ drawfn fn,
+ void *opaque,
+ int *first_row,
+ int *last_row);
+
+#endif
Modified: trunk/hw/omap.h
===================================================================
--- trunk/hw/omap.h 2009-04-01 11:43:02 UTC (rev 6964)
+++ trunk/hw/omap.h 2009-04-01 12:27:59 UTC (rev 6965)
@@ -490,7 +490,7 @@
int dual;
int current_frame;
- ram_addr_t phys_framebuffer[2];
+ target_phys_addr_t phys_framebuffer[2];
qemu_irq irq;
struct omap_mpu_state_s *mpu;
} *omap_dma_get_lcdch(struct soc_dma_s *s);
Modified: trunk/hw/omap_lcd_template.h
===================================================================
--- trunk/hw/omap_lcd_template.h 2009-04-01 11:43:02 UTC (rev 6964)
+++ trunk/hw/omap_lcd_template.h 2009-04-01 12:27:59 UTC (rev 6965)
@@ -43,9 +43,10 @@
/*
* 2-bit colour
*/
-static void glue(draw_line2_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line2_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
+ uint16_t *pal = opaque;
uint8_t v, r, g, b;
do {
@@ -81,9 +82,10 @@
/*
* 4-bit colour
*/
-static void glue(draw_line4_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line4_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
+ uint16_t *pal = opaque;
uint8_t v, r, g, b;
do {
@@ -107,9 +109,10 @@
/*
* 8-bit colour
*/
-static void glue(draw_line8_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line8_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
+ uint16_t *pal = opaque;
uint8_t v, r, g, b;
do {
@@ -126,8 +129,8 @@
/*
* 12-bit colour
*/
-static void glue(draw_line12_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line12_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
uint16_t v;
uint8_t r, g, b;
@@ -146,8 +149,8 @@
/*
* 16-bit colour
*/
-static void glue(draw_line16_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line16_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
memcpy(d, s, width * 2);
Modified: trunk/hw/omap_lcdc.c
===================================================================
--- trunk/hw/omap_lcdc.c 2009-04-01 11:43:02 UTC (rev 6964)
+++ trunk/hw/omap_lcdc.c 2009-04-01 12:27:59 UTC (rev 6965)
@@ -20,6 +20,7 @@
#include "hw.h"
#include "console.h"
#include "omap.h"
+#include "framebuffer.h"
struct omap_lcd_panel_s {
qemu_irq irq;
@@ -68,8 +69,7 @@
#include "pixel_ops.h"
-typedef void draw_line_func(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal);
+#define draw_line_func drawfn
#define DEPTH 8
#include "omap_lcd_template.h"
@@ -80,31 +80,31 @@
#define DEPTH 32
#include "omap_lcd_template.h"
-static draw_line_func *draw_line_table2[33] = {
+static draw_line_func draw_line_table2[33] = {
[0 ... 32] = 0,
[8] = draw_line2_8,
[15] = draw_line2_15,
[16] = draw_line2_16,
[32] = draw_line2_32,
-}, *draw_line_table4[33] = {
+}, draw_line_table4[33] = {
[0 ... 32] = 0,
[8] = draw_line4_8,
[15] = draw_line4_15,
[16] = draw_line4_16,
[32] = draw_line4_32,
-}, *draw_line_table8[33] = {
+}, draw_line_table8[33] = {
[0 ... 32] = 0,
[8] = draw_line8_8,
[15] = draw_line8_15,
[16] = draw_line8_16,
[32] = draw_line8_32,
-}, *draw_line_table12[33] = {
+}, draw_line_table12[33] = {
[0 ... 32] = 0,
[8] = draw_line12_8,
[15] = draw_line12_15,
[16] = draw_line12_16,
[32] = draw_line12_32,
-}, *draw_line_table16[33] = {
+}, draw_line_table16[33] = {
[0 ... 32] = 0,
[8] = draw_line16_8,
[15] = draw_line16_15,
@@ -115,11 +115,10 @@
static void omap_update_display(void *opaque)
{
struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
- draw_line_func *draw_line;
- int size, dirty[2], minline, maxline, height;
- int line, width, linesize, step, bpp, frame_offset;
- ram_addr_t frame_base, scanline, newline, x;
- uint8_t *s, *d;
+ draw_line_func draw_line;
+ int size, height, first, last;
+ int width, linesize, step, bpp, frame_offset;
+ target_phys_addr_t frame_base;
if (!omap_lcd || omap_lcd->plm == 1 ||
!omap_lcd->enable || !ds_get_bits_per_pixel(omap_lcd->state))
@@ -127,9 +126,9 @@
frame_offset = 0;
if (omap_lcd->plm != 2) {
- memcpy(omap_lcd->palette, phys_ram_base +
- omap_lcd->dma->phys_framebuffer[
- omap_lcd->dma->current_frame], 0x200);
+ cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[
+ omap_lcd->dma->current_frame],
+ (void *)omap_lcd->palette, 0x200);
switch (omap_lcd->palette[0] >> 12 & 7) {
case 3 ... 7:
frame_offset += 0x200;
@@ -202,49 +201,28 @@
if (!ds_get_bits_per_pixel(omap_lcd->state))
return;
- line = 0;
+ first = 0;
height = omap_lcd->height;
if (omap_lcd->subpanel & (1 << 31)) {
if (omap_lcd->subpanel & (1 << 29))
- line = (omap_lcd->subpanel >> 16) & 0x3ff;
+ first = (omap_lcd->subpanel >> 16) & 0x3ff;
else
height = (omap_lcd->subpanel >> 16) & 0x3ff;
/* TODO: fill the rest of the panel with DPD */
}
+
step = width * bpp >> 3;
- scanline = frame_base + step * line;
- s = (uint8_t *) (phys_ram_base + scanline);
- d = ds_get_data(omap_lcd->state);
linesize = ds_get_linesize(omap_lcd->state);
-
- dirty[0] = dirty[1] =
- cpu_physical_memory_get_dirty(scanline, VGA_DIRTY_FLAG);
- minline = height;
- maxline = line;
- for (; line < height; line ++) {
- newline = scanline + step;
- for (x = scanline + TARGET_PAGE_SIZE; x < newline;
- x += TARGET_PAGE_SIZE) {
- dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
- dirty[0] |= dirty[1];
- }
- if (dirty[0] || omap_lcd->invalidate) {
- draw_line(d, s, width, omap_lcd->palette);
- if (line < minline)
- minline = line;
- maxline = line + 1;
- }
- scanline = newline;
- dirty[0] = dirty[1];
- s += step;
- d += linesize;
+ framebuffer_update_display(omap_lcd->state,
+ frame_base, width, height,
+ step, linesize, 0,
+ omap_lcd->invalidate,
+ draw_line, omap_lcd->palette,
+ &first, &last);
+ if (first >= 0) {
+ dpy_update(omap_lcd->state, 0, first, width, last - first + 1);
}
-
- if (maxline >= minline) {
- dpy_update(omap_lcd->state, 0, minline, width, maxline);
- cpu_physical_memory_reset_dirty(frame_base + step * minline,
- frame_base + step * maxline, VGA_DIRTY_FLAG);
- }
+ omap_lcd->invalidate = 0;
}
static int ppm_save(const char *filename, uint8_t *data,
@@ -336,25 +314,13 @@
return;
}
- if (s->dma->src == imif) {
- /* Framebuffers are in SRAM */
- s->dma->phys_framebuffer[0] = s->imif_base +
- s->dma->src_f1_top - OMAP_IMIF_BASE;
+ s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
+ s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
- s->dma->phys_framebuffer[1] = s->imif_base +
- s->dma->src_f2_top - OMAP_IMIF_BASE;
- } else {
- /* Framebuffers are in RAM */
- s->dma->phys_framebuffer[0] = s->emiff_base +
- s->dma->src_f1_top - OMAP_EMIFF_BASE;
-
- s->dma->phys_framebuffer[1] = s->emiff_base +
- s->dma->src_f2_top - OMAP_EMIFF_BASE;
- }
-
if (s->plm != 2 && !s->palette_done) {
- memcpy(s->palette, phys_ram_base +
- s->dma->phys_framebuffer[s->dma->current_frame], 0x200);
+ cpu_physical_memory_read(
+ s->dma->phys_framebuffer[s->dma->current_frame],
+ (void *)s->palette, 0x200);
s->palette_done = 1;
omap_lcd_interrupts(s);
}
Modified: trunk/hw/pl110.c
===================================================================
--- trunk/hw/pl110.c 2009-04-01 11:43:02 UTC (rev 6964)
+++ trunk/hw/pl110.c 2009-04-01 12:27:59 UTC (rev 6965)
@@ -10,6 +10,7 @@
#include "hw.h"
#include "primecell.h"
#include "console.h"
+#include "framebuffer.h"
#define PL110_CR_EN 0x001
#define PL110_CR_BGR 0x100
@@ -61,8 +62,6 @@
#include "pixel_ops.h"
-typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int);
-
#define BITS 8
#include "pl110_template.h"
#define BITS 15
@@ -84,17 +83,11 @@
pl110_state *s = (pl110_state *)opaque;
drawfn* fntable;
drawfn fn;
- uint32_t *pallette;
- uint32_t addr;
- uint32_t base;
int dest_width;
int src_width;
- uint8_t *dest;
- uint8_t *src;
- int first, last = 0;
- int dirty, new_dirty;
- int i;
int bpp_offset;
+ int first;
+ int last;
if (!pl110_enabled(s))
return;
@@ -159,47 +152,17 @@
break;
}
dest_width *= s->cols;
- pallette = s->pallette;
- base = s->upbase;
- /* HACK: Arm aliases physical memory at 0x80000000. */
- if (base > 0x80000000)
- base -= 0x80000000;
- src = phys_ram_base + base;
- dest = ds_get_data(s->ds);
- first = -1;
- addr = base;
-
- dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
- new_dirty = dirty;
- for (i = 0; i < s->rows; i++) {
- if ((addr & ~TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) {
- uint32_t tmp;
- new_dirty = 0;
- for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) {
- new_dirty |= cpu_physical_memory_get_dirty(addr + tmp,
- VGA_DIRTY_FLAG);
- }
- }
-
- if (dirty || new_dirty || s->invalidate) {
- fn(pallette, dest, src, s->cols);
- if (first == -1)
- first = i;
- last = i;
- }
- dirty = new_dirty;
- addr += src_width;
- dest += dest_width;
- src += src_width;
+ first = 0;
+ framebuffer_update_display(s->ds,
+ s->upbase, s->cols, s->rows,
+ src_width, dest_width, 0,
+ s->invalidate,
+ fn, s->pallette,
+ &first, &last);
+ if (first >= 0) {
+ dpy_update(s->ds, 0, first, s->cols, last - first + 1);
}
- if (first < 0)
- return;
-
s->invalidate = 0;
- cpu_physical_memory_reset_dirty(base + first * src_width,
- base + (last + 1) * src_width,
- VGA_DIRTY_FLAG);
- dpy_update(s->ds, 0, first, s->cols, last - first + 1);
}
static void pl110_invalidate_display(void * opaque)
Modified: trunk/hw/pl110_template.h
===================================================================
--- trunk/hw/pl110_template.h 2009-04-01 11:43:02 UTC (rev 6964)
+++ trunk/hw/pl110_template.h 2009-04-01 12:27:59 UTC (rev 6965)
@@ -115,8 +115,9 @@
#define FN_4(x, y) FN_2(x, y) FN_2(x+2, y)
#define FN_8(y) FN_4(0, y) FN_4(4, y)
-static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
+ uint32_t *pallette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
@@ -142,8 +143,9 @@
}
}
-static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
+ uint32_t *pallette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
@@ -169,8 +171,9 @@
}
}
-static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
+ uint32_t *pallette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
@@ -196,8 +199,9 @@
}
}
-static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
+ uint32_t *pallette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
@@ -219,7 +223,7 @@
}
}
-static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line16_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
uint32_t data;
unsigned int r, g, b;
@@ -265,7 +269,7 @@
}
}
-static void glue(pl110_draw_line32_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line32_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
uint32_t data;
unsigned int r, g, b;
Modified: trunk/hw/pxa2xx_lcd.c
===================================================================
--- trunk/hw/pxa2xx_lcd.c 2009-04-01 11:43:02 UTC (rev 6964)
+++ trunk/hw/pxa2xx_lcd.c 2009-04-01 12:27:59 UTC (rev 6965)
@@ -13,9 +13,8 @@
#include "pixel_ops.h"
/* FIXME: For graphic_rotate. Should probably be done in common code. */
#include "sysemu.h"
+#include "framebuffer.h"
-typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int);
-
struct pxa2xx_lcdc_s {
qemu_irq irq;
int irqlevel;
@@ -56,7 +55,7 @@
int up;
uint8_t palette[1024];
uint8_t pbuffer[1024];
- void (*redraw)(struct pxa2xx_lcdc_s *s, uint8_t *fb,
+ void (*redraw)(struct pxa2xx_lcdc_s *s, target_phys_addr_t addr,
int *miny, int *maxy);
target_phys_addr_t descriptor;
@@ -669,18 +668,15 @@
}
static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s,
- uint8_t *fb, int *miny, int *maxy)
+ target_phys_addr_t addr, int *miny, int *maxy)
{
- int y, src_width, dest_width, dirty[2];
- uint8_t *src, *dest;
- ram_addr_t x, addr, new_addr, start, end;
+ int src_width, dest_width;
drawfn fn = 0;
if (s->dest_width)
fn = s->line_fn[s->transp][s->bpp];
if (!fn)
return;
- src = fb;
src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
src_width *= 3;
@@ -689,54 +685,25 @@
else if (s->bpp > pxa_lcdc_8bpp)
src_width *= 2;
- dest = ds_get_data(s->ds);
dest_width = s->xres * s->dest_width;
-
- addr = (ram_addr_t) (fb - phys_ram_base);
- start = addr + s->yres * src_width;
- end = addr;
- dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
- for (y = 0; y < s->yres; y ++) {
- new_addr = addr + src_width;
- for (x = addr + TARGET_PAGE_SIZE; x < new_addr;
- x += TARGET_PAGE_SIZE) {
- dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
- dirty[0] |= dirty[1];
- }
- if (dirty[0] || s->invalidated) {
- fn((uint32_t *) s->dma_ch[0].palette,
- dest, src, s->xres, s->dest_width);
- if (addr < start)
- start = addr;
- end = new_addr;
- if (y < *miny)
- *miny = y;
- if (y >= *maxy)
- *maxy = y + 1;
- }
- addr = new_addr;
- dirty[0] = dirty[1];
- src += src_width;
- dest += dest_width;
- }
-
- if (end > start)
- cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+ *miny = 0;
+ framebuffer_update_display(s->ds,
+ addr, s->xres, s->yres,
+ src_width, dest_width, s->dest_width,
+ s->invalidated,
+ fn, s->dma_ch[0].palette, miny, maxy);
}
static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s,
- uint8_t *fb, int *miny, int *maxy)
+ target_phys_addr_t addr, int *miny, int *maxy)
{
- int y, src_width, dest_width, dirty[2];
- uint8_t *src, *dest;
- ram_addr_t x, addr, new_addr, start, end;
+ int src_width, dest_width;
drawfn fn = 0;
if (s->dest_width)
fn = s->line_fn[s->transp][s->bpp];
if (!fn)
return;
- src = fb;
src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
src_width *= 3;
@@ -746,38 +713,13 @@
src_width *= 2;
dest_width = s->yres * s->dest_width;
- dest = ds_get_data(s->ds) + dest_width * (s->xres - 1);
-
- addr = (ram_addr_t) (fb - phys_ram_base);
- start = addr + s->yres * src_width;
- end = addr;
- x = addr + TARGET_PAGE_SIZE;
- dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
- for (y = 0; y < s->yres; y ++) {
- new_addr = addr + src_width;
- for (; x < new_addr; x += TARGET_PAGE_SIZE) {
- dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
- dirty[0] |= dirty[1];
- }
- if (dirty[0] || s->invalidated) {
- fn((uint32_t *) s->dma_ch[0].palette,
- dest, src, s->xres, -dest_width);
- if (addr < start)
- start = addr;
- end = new_addr;
- if (y < *miny)
- *miny = y;
- if (y >= *maxy)
- *maxy = y + 1;
- }
- addr = new_addr;
- dirty[0] = dirty[1];
- src += src_width;
- dest += s->dest_width;
- }
-
- if (end > start)
- cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+ *miny = 0;
+ framebuffer_update_display(s->ds,
+ addr, s->xres, s->yres,
+ src_width, s->dest_width, -dest_width,
+ s->invalidated,
+ fn, s->dma_ch[0].palette,
+ miny, maxy);
}
static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
@@ -803,7 +745,6 @@
static void pxa2xx_update_display(void *opaque)
{
struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
- uint8_t *fb;
target_phys_addr_t fbptr;
int miny, maxy;
int ch;
@@ -829,13 +770,11 @@
pxa2xx_dma_ber_set(s, ch);
continue;
}
- fbptr -= PXA2XX_SDRAM_BASE;
- fb = phys_ram_base + fbptr;
if (s->dma_ch[ch].command & LDCMD_PAL) {
- memcpy(s->dma_ch[ch].pbuffer, fb,
- MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
- sizeof(s->dma_ch[ch].pbuffer)));
+ cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
+ MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
+ sizeof(s->dma_ch[ch].pbuffer)));
pxa2xx_palette_parse(s, ch, s->bpp);
} else {
/* Do we need to reparse palette */
@@ -845,7 +784,7 @@
/* ACK frame start */
pxa2xx_dma_sof_set(s, ch);
- s->dma_ch[ch].redraw(s, fb, &miny, &maxy);
+ s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
s->invalidated = 0;
/* ACK frame completed */
@@ -859,10 +798,12 @@
s->status[0] |= LCSR0_LDD;
}
- if (s->orientation)
- dpy_update(s->ds, miny, 0, maxy, s->xres);
- else
- dpy_update(s->ds, 0, miny, s->xres, maxy);
+ if (miny >= 0) {
+ if (s->orientation)
+ dpy_update(s->ds, miny, 0, maxy, s->xres);
+ else
+ dpy_update(s->ds, 0, miny, s->xres, maxy);
+ }
pxa2xx_lcdc_int_update(s);
qemu_irq_raise(s->vsync_cb);
Modified: trunk/hw/pxa2xx_template.h
===================================================================
--- trunk/hw/pxa2xx_template.h 2009-04-01 11:43:02 UTC (rev 6964)
+++ trunk/hw/pxa2xx_template.h 2009-04-01 12:27:59 UTC (rev 6965)
@@ -30,9 +30,10 @@
#define FN_2(x) FN(x + 1) FN(x)
#define FN_4(x) FN_2(x + 2) FN_2(x)
-static void glue(pxa2xx_draw_line2_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line2_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *) src;
@@ -54,9 +55,10 @@
}
}
-static void glue(pxa2xx_draw_line4_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line4_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *) src;
@@ -78,9 +80,10 @@
}
}
-static void glue(pxa2xx_draw_line8_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line8_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *) src;
@@ -102,7 +105,7 @@
}
}
-static void glue(pxa2xx_draw_line16_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line16_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -130,7 +133,7 @@
}
}
-static void glue(pxa2xx_draw_line16t_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line16t_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -166,7 +169,7 @@
}
}
-static void glue(pxa2xx_draw_line18_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line18_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -188,7 +191,7 @@
}
/* The wicked packed format */
-static void glue(pxa2xx_draw_line18p_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line18p_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data[3];
@@ -236,7 +239,7 @@
}
}
-static void glue(pxa2xx_draw_line19_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line19_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -262,7 +265,7 @@
}
/* The wicked packed format */
-static void glue(pxa2xx_draw_line19p_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line19p_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data[3];
@@ -326,7 +329,7 @@
}
}
-static void glue(pxa2xx_draw_line24_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line24_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -347,7 +350,7 @@
}
}
-static void glue(pxa2xx_draw_line24t_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line24t_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -372,7 +375,7 @@
}
}
-static void glue(pxa2xx_draw_line25_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line25_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] [6965] Implement and use shared memory framebuffer device rendering reoutine.
2009-04-01 12:28 [Qemu-devel] [6965] Implement and use shared memory framebuffer device rendering reoutine Paul Brook
@ 2009-04-02 20:52 ` andrzej zaborowski
2009-04-02 22:33 ` Paul Brook
0 siblings, 1 reply; 3+ messages in thread
From: andrzej zaborowski @ 2009-04-02 20:52 UTC (permalink / raw)
To: qemu-devel
2009/4/1 Paul Brook <paul@nowt.org>:
> Revision: 6965
> http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=6965
> Author: pbrook
> Date: 2009-04-01 12:27:59 +0000 (Wed, 01 Apr 2009)
> Log Message:
> -----------
> Implement and use shared memory framebuffer device rendering reoutine.
> Use DMA mapping API.
>
> Signed-off-by: Paul Brook <paul@codesourcery.com>
>
> Modified Paths:
> --------------
> trunk/Makefile.target
> trunk/hw/omap.h
> trunk/hw/omap_lcd_template.h
> trunk/hw/omap_lcdc.c
> trunk/hw/pl110.c
> trunk/hw/pl110_template.h
> trunk/hw/pxa2xx_lcd.c
> trunk/hw/pxa2xx_template.h
>
> Added Paths:
> -----------
> trunk/hw/framebuffer.c
> trunk/hw/framebuffer.h
>
> Modified: trunk/Makefile.target
> ===================================================================
> --- trunk/Makefile.target 2009-04-01 11:43:02 UTC (rev 6964)
> +++ trunk/Makefile.target 2009-04-01 12:27:59 UTC (rev 6965)
> @@ -672,6 +672,7 @@
> OBJS+= tsc2005.o bt-hci-csr.o
> OBJS+= mst_fpga.o mainstone.o
> OBJS+= musicpal.o pflash_cfi02.o
> +OBJS+= framebuffer.o
> CPPFLAGS += -DHAS_AUDIO
> endif
> ifeq ($(TARGET_BASE_ARCH), sh4)
>
> Added: trunk/hw/framebuffer.c
> ===================================================================
> --- trunk/hw/framebuffer.c (rev 0)
> +++ trunk/hw/framebuffer.c 2009-04-01 12:27:59 UTC (rev 6965)
> @@ -0,0 +1,119 @@
> +/*
> + * Framebuffer device helper routines
> + *
> + * Copyright (c) 2009 CodeSourcery
> + * Written by Paul Brook <paul@codesourcery.com>
> + *
> + * This code is licensed under the GNU GPLv2.
> + */
> +
> +/* TODO:
> + - Do something similar for framebuffers with local ram
> + - Handle rotation here instead of hacking dest_pitch
> + - Use common pixel conversion routines instead of per-device drawfn
> + - Remove all DisplayState knowledge from devices.
> + */
> +
> +#include "hw.h"
> +#include "console.h"
> +#include "framebuffer.h"
> +#include "kvm.h"
> +
> +/* Render an image from a shared memory framebuffer. */
> +
> +void framebuffer_update_display(
> + DisplayState *ds,
> + target_phys_addr_t base,
> + int cols, /* Width in pixels. */
> + int rows, /* Leight in pixels. */
> + int src_width, /* Length of source line, in bytes. */
> + int dest_row_pitch, /* Bytes between adjacent horizontal output pixels. */
> + int dest_col_pitch, /* Bytes between adjacent vertical output pixels. */
> + int invalidate, /* nonzero to redraw the whole image. */
> + drawfn fn,
> + void *opaque,
> + int *first_row, /* Input and output. */
> + int *last_row /* Output only */)
> +{
> + target_phys_addr_t src_len;
> + uint8_t *dest;
> + uint8_t *src;
> + uint8_t *src_base;
> + int first, last = 0;
> + int dirty;
> + int i;
> + ram_addr_t addr;
> + ram_addr_t pd;
> + ram_addr_t pd2;
> +
> + i = *first_row;
> + *first_row = -1;
> + src_len = src_width * rows;
> +
> + if (kvm_enabled()) {
> + kvm_physical_sync_dirty_bitmap(base, src_len);
> + }
> + pd = cpu_get_physical_page_desc(base);
> + pd2 = cpu_get_physical_page_desc(base + src_len - 1);
> + /* We should reall check that this is a continuous ram region.
> + Instead we just check that the first and last pages are
> + both ram, and the right distance apart. */
> + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM
> + || (pd2 & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
> + return;
> + }
> + pd = (pd & TARGET_PAGE_MASK) + (base & ~TARGET_PAGE_MASK);
> + if (((pd + src_len - 1) & TARGET_PAGE_MASK) != (pd2 & TARGET_PAGE_MASK)) {
> + return;
> + }
> +
> + src_base = cpu_physical_memory_map(base, &src_len, 0);
> + /* If we can't map the framebuffer then bail. We could try harder,
> + but it's not really worth it as dirty flag tracking will probably
> + already have failed above. */
> + if (!src_base)
> + return;
> + if (src_len != src_width * rows) {
> + cpu_physical_memory_unmap(src_base, src_len, 0, 0);
> + return;
> + }
> + src = src_base;
> + dest = ds_get_data(ds);
> + if (dest_col_pitch < 0)
> + dest -= dest_col_pitch * (cols - 1);
> + first = -1;
> + addr = pd;
If we must use the map/unmap api for framebuffers (even though we know
this memory is continuous in qemu) then we could map omly the region
we determined is dirty.
Cheers
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] [6965] Implement and use shared memory framebuffer device rendering reoutine.
2009-04-02 20:52 ` andrzej zaborowski
@ 2009-04-02 22:33 ` Paul Brook
0 siblings, 0 replies; 3+ messages in thread
From: Paul Brook @ 2009-04-02 22:33 UTC (permalink / raw)
To: qemu-devel
> If we must use the map/unmap api for framebuffers (even though we know
> this memory is continuous in qemu) then we could map only the region
> we determined is dirty.
Maybe. In practice I doubt there's that much difference. In general we don't
actually know the memory is contiguous, though for well behaved guests with
current boards it probably is. The proper solution is probably to replace
l1_phys_map with an extent bases system, so that map time is not proportional
to region size.
My main motivation for this patch is that it is the first step in eliminating
phys_ram_base.
Paul
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2009-04-02 22:33 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-01 12:28 [Qemu-devel] [6965] Implement and use shared memory framebuffer device rendering reoutine Paul Brook
2009-04-02 20:52 ` andrzej zaborowski
2009-04-02 22:33 ` Paul Brook
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).