[Spice-devel] [PATCH] spice: split heavily clipped images into small images (speed win7)

Izik Eidus ieidus at redhat.com
Tue Feb 16 10:31:26 PST 2010


From 5d35a1c6e59102e037499c33f95f7c6e590d27d2 Mon Sep 17 00:00:00 2001
From: Izik Eidus <ieidus at redhat.com>
Date: Tue, 16 Feb 2010 20:30:14 +0200
Subject: [PATCH] spice: split heavily clipped images into small images (speed win7)

This really speed up windows 7

Thanks

Signed-off-by: Izik Eidus <ieidus at redhat.com>
---
 display/res.c |   72 +++++++++++++++++++++++++++-----
 display/res.h |    1 +
 display/rop.c |  130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 190 insertions(+), 13 deletions(-)

diff --git a/display/res.c b/display/res.c
index 4b1a2fd..2b0735a 100644
--- a/display/res.c
+++ b/display/res.c
@@ -890,7 +890,6 @@ static CacheImage *ImageCacheGetByKey(PDev *pdev, UINT32 key, BOOL check_rest,
     while (cache_image) {
         if (cache_image->key == key && (!check_rest || (cache_image->format == format &&
             cache_image->width == width && cache_image->height == height))) {
-            cache_image->hits++;
             return cache_image;
         }
         cache_image = cache_image->next;
@@ -1411,16 +1410,10 @@ static BOOL ChachSizeTest(PDev *pdev, SURFOBJ *surf)
     return ret;
 }
 
-
-static CacheImage *GetChachImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans, UINT32 *hash_key)
+static _inline UINT64 get_unique(SURFOBJ *surf, XLATEOBJ *color_trans)
 {
-    CacheImage *cache_image;
-    ULONG pallette_unique;
-    UINT64 gdi_unique;
     int pallette;
-    UINT32 key;
-    UINT8 format;
-    UINT32 line_size;
+    ULONG pallette_unique;
 
     pallette = color_trans && (color_trans->flXlate & XO_TABLE);
     pallette_unique = pallette ? color_trans->iUniq : 0;
@@ -1428,11 +1421,65 @@ static CacheImage *GetChachImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_tran
     // NOTE: GDI sometimes gives many instances of the exactly same SURFOBJ (hsurf & iUniq),
     // but with (fjBitmap & BMF_DONTCACHE). This opposed to what documented in the MSDN.
     if (!surf->iUniq || (surf->fjBitmap & BMF_DONTCACHE) || (pallette && !pallette_unique)) {
-        gdi_unique = 0;
+        return 0;
     } else {
-        gdi_unique = surf->iUniq | ((UINT64)pallette_unique << 32);
+        return (surf->iUniq | ((UINT64)pallette_unique << 32));
+    }
+}
+
+BOOL CheckIfCacheImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans)
+{
+    CacheImage *cache_image;
+    UINT64 gdi_unique;
+    UINT32 key;
+    UINT8 format;
+
+    gdi_unique = get_unique(surf, color_trans);
+
+    if (!ImageKeyGet(pdev, surf->hsurf, gdi_unique, &key)) {
+        return FALSE;
+    }
+
+    switch (surf->iBitmapFormat) {
+    case BMF_32BPP:
+        format = SPICE_BITMAP_FMT_32BIT;
+        break;
+    case BMF_24BPP:
+        format = SPICE_BITMAP_FMT_24BIT;
+        break;
+    case BMF_16BPP:
+        format = SPICE_BITMAP_FMT_16BIT;
+        break;
+    case BMF_8BPP:
+        format = SPICE_BITMAP_FMT_8BIT;
+        break;
+    case BMF_4BPP:
+        format = SPICE_BITMAP_FMT_4BIT_BE;
+        break;
+    case BMF_1BPP:
+        format = SPICE_BITMAP_FMT_1BIT_BE;
+    }
+
+
+    if ((cache_image = ImageCacheGetByKey(pdev, key, TRUE, format,
+                                          surf->sizlBitmap.cx,
+                                          surf->sizlBitmap.cy))) {
+        return TRUE;
     }
 
+    return FALSE;
+}
+
+static CacheImage *GetChachImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans, UINT32 *hash_key)
+{
+    CacheImage *cache_image;
+    UINT64 gdi_unique;
+    UINT32 key;
+    UINT8 format;
+    UINT32 line_size;
+
+    gdi_unique = get_unique(surf, color_trans);
+
     if (!(line_size = GetFormatLineSize(surf->sizlBitmap.cx, surf->iBitmapFormat, &format))) {
         DEBUG_PRINT((pdev, 0, "%s: bitmap format err\n", __FUNCTION__));
         return FALSE;
@@ -1454,6 +1501,7 @@ static CacheImage *GetChachImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_tran
     if ((cache_image = ImageCacheGetByKey(pdev, key, TRUE, format,
                                           surf->sizlBitmap.cx,
                                           surf->sizlBitmap.cy))) {
+        cache_image->hits++;
         DEBUG_PRINT((pdev, 11, "%s: ImageCacheGetByKey %u hits %u\n", __FUNCTION__,
                      key, cache_image->hits));
         return cache_image;
@@ -1653,6 +1701,7 @@ BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phy
                                          surf->sizlBitmap.cx, surf->sizlBitmap.cy)) {
         DEBUG_PRINT((pdev, 11, "%s: ImageCacheGetByKey %u hits %u\n", __FUNCTION__,
                      key, cache_image->hits));
+        cache_image->hits++;
         if (internal = cache_image->image) {
             DEBUG_PRINT((pdev, 11, "%s: cached image found %u\n", __FUNCTION__, key));
             *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
@@ -1712,6 +1761,7 @@ BOOL QXLGetBitsFromCache(PDev *pdev, QXLDrawable *drawable, UINT32 hash_key, QXL
 
     if ((cache_image = ImageCacheGetByKey(pdev, hash_key, FALSE, 0, 0, 0)) &&
         (internal = cache_image->image)) {
+        cache_image->hits++;
         *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
         image_res = (Resource *)((UINT8 *)internal - sizeof(Resource));
         DrawableAddRes(pdev, drawable, image_res);
diff --git a/display/res.h b/display/res.h
index bc18d1f..e181434 100644
--- a/display/res.h
+++ b/display/res.h
@@ -37,6 +37,7 @@ BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SU
 BOOL QXLGetBitsFromCache(PDev *pdev, QXLDrawable *drawable, UINT32 hash_key, QXLPHYSICAL *image_phys);
 BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
                        SpiceRect *area);
+BOOL CheckIfCacheImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans);
 UINT8 *QXLGetBuf(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *buf_phys, UINT32 size);
 BOOL QXLGetStr(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *str_phys, FONTOBJ *font, STROBJ *str);
 
diff --git a/display/rop.c b/display/rop.c
index b9b25b8..746dd6a 100644
--- a/display/rop.c
+++ b/display/rop.c
@@ -514,6 +514,96 @@ static BOOL StreamTest(PDev *pdev, SURFOBJ *src_surf, XLATEOBJ *color_trans, REC
     return TRUE;
 }
 
+static BOOL TestSplitClips(PDev *pdev, RECTL *src_rect, CLIPOBJ *clip, SURFOBJ *mask)
+{
+    UINT32 width;
+    UINT32 height;
+    UINT32 src_space;
+    UINT32 clip_space = 0;
+    int more;
+
+    if (!clip || mask) {
+        return FALSE;
+    }
+
+    width = src_rect->right - src_rect->left;
+    height = src_rect->bottom - src_rect->top;
+    src_space = width * height;
+
+    if (clip->iDComplexity == DC_RECT) {
+        width = clip->rclBounds.right - clip->rclBounds.left;
+        height = clip->rclBounds.bottom - clip->rclBounds.top;
+        clip_space = width * height;
+
+        if ((src_space / clip_space) > 1) {
+            return TRUE;
+        }
+        return FALSE;
+    }
+
+    if (clip->iMode == TC_RECTANGLES) {
+        CLIPOBJ_cEnumStart(clip, TRUE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
+        do {
+            RECTL *now;
+            RECTL *end;
+
+            struct {
+                ULONG  count;
+                RECTL  rects[20];
+            } buf;
+
+            more = CLIPOBJ_bEnum(clip, sizeof(buf), (ULONG *)&buf);
+            for(now = buf.rects, end = now + buf.count; now < end; now++) {
+                width = now->right - now->left;
+                height = now->bottom - now->top;
+                clip_space += width * height;
+            }
+        } while (more);
+
+        if ((src_space / clip_space) > 1) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static _inline BOOL DoPartialCopy(PDev *pdev, SURFOBJ *src, RECTL *src_rect, RECTL *area_rect,
+                                  RECTL *clip_rect, XLATEOBJ *color_trans, ULONG scale_mode,
+                                  UINT16 rop_decriptor)
+{
+    QXLDrawable *drawable;
+    RECTL clip_area;
+
+    SectRect(area_rect, clip_rect, &clip_area);
+    if (IsEmptyRect(&clip_area)) {
+        return TRUE;
+    }
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, &clip_area, NULL))) {
+        return FALSE;
+    }
+
+    drawable->effect = QXL_EFFECT_OPAQUE;
+    drawable->u.copy.scale_mode = GdiScaleModeToQxl(scale_mode);
+    drawable->u.copy.mask.bitmap = 0;
+    drawable->u.copy.rop_decriptor = rop_decriptor;
+
+    drawable->u.copy.src_area.top = src_rect->top + (clip_area.top - area_rect->top);
+    drawable->u.copy.src_area.bottom = drawable->u.copy.src_area.top + clip_area.bottom -
+                                       clip_area.top;
+    drawable->u.copy.src_area.left = src_rect->left + (clip_area.left - area_rect->left);
+    drawable->u.copy.src_area.right = drawable->u.copy.src_area.left + clip_area.right -
+                                      clip_area.left;
+
+    if(!GetBitmap(pdev, drawable, &drawable->u.copy.src_bitmap, src, &drawable->u.copy.src_area,
+                  color_trans, FALSE)) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
 static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
                    XLATEOBJ *color_trans, UINT16 rop_decriptor, SURFOBJ *mask, POINTL *mask_pos,
                    BOOL invers_mask, ULONG scale_mode)
@@ -524,16 +614,52 @@ static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *
     ASSERT(pdev, pdev && area && src_rect && src);
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
 
+    if (mask) {
+        use_cache = TRUE;
+    } else {
+        use_cache = StreamTest(pdev, src, color_trans, src_rect, area);
+    }
+
+    if (use_cache && TestSplitClips(pdev, src_rect, clip, mask) &&
+        !CheckIfCacheImage(pdev, src, color_trans)) {
+
+        if (clip->iDComplexity == DC_RECT) {
+            if (!DoPartialCopy(pdev, src, src_rect, area, &clip->rclBounds, color_trans, scale_mode,
+                               rop_decriptor)) {
+                return FALSE;
+            }
+        } else {
+            int more;
+            ASSERT(pdev, clip->iMode == TC_RECTANGLES);
+            CLIPOBJ_cEnumStart(clip, TRUE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
+            do {
+                RECTL *now;
+                RECTL *end;
+
+                struct {
+                    ULONG  count;
+                    RECTL  rects[20];
+                } buf;
+                more = CLIPOBJ_bEnum(clip, sizeof(buf), (ULONG *)&buf);
+                for(now = buf.rects, end = now + buf.count; now < end; now++) {
+                    if (!DoPartialCopy(pdev, src, src_rect, area, now, color_trans, scale_mode,
+                                       rop_decriptor)) {
+                        return FALSE;
+                    }
+                }
+            } while (more);
+        }
+        return TRUE;
+    }
+
     if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, area, clip))) {
         return FALSE;
     }
 
     if (mask) {
         drawable->effect = QXL_EFFECT_BLEND;
-        use_cache = TRUE;
     } else {
         drawable->effect = QXL_EFFECT_OPAQUE;
-        use_cache = StreamTest(pdev, src, color_trans, src_rect, area);
     }
 
     drawable->u.copy.scale_mode = GdiScaleModeToQxl(scale_mode);
-- 
1.6.6.1



More information about the Spice-devel mailing list