summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/cirrus_vga.c83
1 files changed, 79 insertions, 4 deletions
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 934cde9905..d186d797ac 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -644,15 +644,90 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
                                             (s->cirrus_blt_srcaddr & ~7));
 }
 
-static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
+static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
 {
+    int sx, sy;
+    int dx, dy;
+    int width, height;
+    int depth;
+    int notify = 0;
+
+    depth = s->get_bpp((VGAState *)s) / 8;
+    s->get_resolution((VGAState *)s, &width, &height);
+
+    /* extra x, y */
+    sx = (src % (width * depth)) / depth;
+    sy = (src / (width * depth));
+    dx = (dst % (width *depth)) / depth;
+    dy = (dst / (width * depth));
+
+    /* normalize width */
+    w /= depth;
+
+    /* if we're doing a backward copy, we have to adjust
+       our x/y to be the upper left corner (instead of the lower
+       right corner) */
+    if (s->cirrus_blt_dstpitch < 0) {
+	sx -= (s->cirrus_blt_width / depth) - 1;
+	dx -= (s->cirrus_blt_width / depth) - 1;
+	sy -= s->cirrus_blt_height - 1;
+	dy -= s->cirrus_blt_height - 1;
+    }
+
+    /* are we in the visible portion of memory? */
+    if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
+	(sx + w) <= width && (sy + h) <= height &&
+	(dx + w) <= width && (dy + h) <= height) {
+	notify = 1;
+    }
+
+    /* make to sure only copy if it's a plain copy ROP */
+    if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src &&
+	*s->cirrus_rop != cirrus_bitblt_rop_bkwd_src)
+	notify = 0;
+
+    /* we have to flush all pending changes so that the copy
+       is generated at the appropriate moment in time */
+    if (notify)
+	vga_hw_update();
+
     (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
 		      s->vram_ptr + s->cirrus_blt_srcaddr,
 		      s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
 		      s->cirrus_blt_width, s->cirrus_blt_height);
-    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
-			     s->cirrus_blt_dstpitch, s->cirrus_blt_width,
-			     s->cirrus_blt_height);
+
+    if (notify)
+	s->ds->dpy_copy(s->ds,
+			sx, sy, dx, dy,
+			s->cirrus_blt_width / depth,
+			s->cirrus_blt_height);
+
+    /* we don't have to notify the display that this portion has
+       changed since dpy_copy implies this */
+
+    if (!notify)
+	cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+				 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+				 s->cirrus_blt_height);
+}
+
+static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
+{
+    if (s->ds->dpy_copy) {
+	cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
+		       s->cirrus_blt_srcaddr - s->start_addr,
+		       s->cirrus_blt_width, s->cirrus_blt_height);
+    } else {
+	(*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
+			  s->vram_ptr + s->cirrus_blt_srcaddr,
+			  s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
+			  s->cirrus_blt_width, s->cirrus_blt_height);
+
+	cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+				 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+				 s->cirrus_blt_height);
+    }
+
     return 1;
 }