]> git.proxmox.com Git - qemu.git/blobdiff - hw/sm501.c
Merge remote-tracking branch 'spice/spice.v39' into staging
[qemu.git] / hw / sm501.c
index f16e6e4e6582b070063d3c511773f483afd78225..0f0bf96609b0dcedccda4f518816ccc8aef890ce 100644 (file)
@@ -511,6 +511,7 @@ typedef struct SM501State {
     uint32_t dc_crt_hwc_color_1_2;
     uint32_t dc_crt_hwc_color_3;
 
+    uint32_t twoD_source;
     uint32_t twoD_destination;
     uint32_t twoD_dimension;
     uint32_t twoD_control;
@@ -636,6 +637,9 @@ static void sm501_2d_operation(SM501State * s)
 {
     /* obtain operation parameters */
     int operation = (s->twoD_control >> 16) & 0x1f;
+    int rtl = s->twoD_control & 0x8000000;
+    int src_x = (s->twoD_source >> 16) & 0x01FFF;
+    int src_y = s->twoD_source & 0xFFFF;
     int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
     int dst_y = s->twoD_destination & 0xFFFF;
     int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
@@ -645,10 +649,9 @@ static void sm501_2d_operation(SM501State * s)
     int addressing = (s->twoD_stretch >> 16) & 0xF;
 
     /* get frame buffer info */
-#if 0 /* for future use */
     uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
-#endif
     uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
+    int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
     int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
 
     if (addressing != 0x0) {
@@ -663,8 +666,36 @@ static void sm501_2d_operation(SM501State * s)
     }
 
     switch (operation) {
-    case 0x01: /* fill rectangle */
+    case 0x00: /* copy area */
+#define COPY_AREA(_bpp, _pixel_type, rtl) {                                 \
+        int y, x, index_d, index_s;                                         \
+        for (y = 0; y < operation_height; y++) {                            \
+            for (x = 0; x < operation_width; x++) {                         \
+                if (rtl) {                                                  \
+                    index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
+                    index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
+                } else {                                                    \
+                    index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
+                    index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+                }                                                           \
+                *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
+            }                                                               \
+        }                                                                   \
+    }
+        switch (format_flags) {
+        case 0:
+            COPY_AREA(1, uint8_t, rtl);
+            break;
+        case 1:
+            COPY_AREA(2, uint16_t, rtl);
+            break;
+        case 2:
+            COPY_AREA(4, uint32_t, rtl);
+            break;
+        }
+        break;
 
+    case 0x01: /* fill rectangle */
 #define FILL_RECT(_bpp, _pixel_type) {                                      \
         int y, x;                                                           \
         for (y = 0; y < operation_height; y++) {                            \
@@ -1072,6 +1103,9 @@ static void sm501_2d_engine_write(void *opaque,
                   addr, value);
 
     switch(addr) {
+    case SM501_2D_SOURCE:
+        s->twoD_source = value;
+        break;
     case SM501_2D_DESTINATION:
         s->twoD_destination = value;
         break;
@@ -1240,8 +1274,8 @@ static void sm501_draw_crt(SM501State * s)
     draw_hwc_line_func * draw_hwc_line = NULL;
     int full_update = 0;
     int y_start = -1;
-    int page_min = 0x7fffffff;
-    int page_max = -1;
+    ram_addr_t page_min = ~0l;
+    ram_addr_t page_max = 0l;
     ram_addr_t offset = s->local_mem_offset;
 
     /* choose draw_line function */
@@ -1337,9 +1371,10 @@ static void sm501_draw_crt(SM501State * s)
        dpy_update(s->ds, 0, y_start, width, y - y_start);
 
     /* clear dirty flags */
-    if (page_max != -1)
+    if (page_min != ~0l) {
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
                                        VGA_DIRTY_FLAG);
+    }
 }
 
 static void sm501_update_display(void *opaque)