[Spice-devel] [PATCH qxl-win v4 1/3] display/surface: add surfaces from/to ram

Alon Levy alevy at redhat.com
Wed Jul 27 09:17:21 PDT 2011


Adds fields to SurfaceInfo to cache data previously only available
via SurfaceArea::draw_area.

Adds two functions to save and restore surfaces from ram:

MoveAllSurfacesToVideoRam
 allocates and copies surfaces from vram to ram, and calls EngModifySurface
 with an empty hook list to make those surfaces completely managed by gdi and not
 us.

MoveAllSurfacesToRam
 recreates surfaces on vram and calls EngModifySurface with QXL_SURFACE_HOOKS, and
 finally sends a QXL_SURFACE_CMD_CREATE with the valid data flag to make the server
 send a surface image message after the surface create message.

Cc: Yonit Halperin <yhalperi at redhat.com>
---
 display/driver.c  |    4 +-
 display/qxldd.h   |    6 +-
 display/res.c     |   10 ++-
 display/res.h     |    3 +-
 display/surface.c |  266 +++++++++++++++++++++++++++++++++++++++++++++--------
 display/surface.h |    3 +
 6 files changed, 248 insertions(+), 44 deletions(-)

diff --git a/display/driver.c b/display/driver.c
index d5f9d8c..6b12540 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -1300,7 +1300,9 @@ VOID APIENTRY DrvDeleteDeviceBitmap(DHSURF dhsurf)
 
     ASSERT(pdev, surface_id < pdev->n_surfaces);
 
-    DeleteDeviceBitmap(surface->u.pdev, surface_id, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+    DeleteDeviceBitmap(surface->u.pdev, surface_id,
+                       surface->copy ? DEVICE_BITMAP_ALLOCATION_TYPE_RAM
+                                     : DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
 }
 
 #ifdef CALL_TEST
diff --git a/display/qxldd.h b/display/qxldd.h
index 92d1ae8..c9c2300 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -187,7 +187,11 @@ typedef struct DrawArea {
 
 typedef struct SurfaceInfo SurfaceInfo;
 struct SurfaceInfo {
-    DrawArea draw_area;
+    DrawArea    draw_area;
+    HBITMAP     hbitmap;
+    SIZEL       size;
+    UINT8      *copy;
+    ULONG       bitmap_format;
     union {
         PDev *pdev;
         SurfaceInfo *next_free;
diff --git a/display/res.c b/display/res.c
index c21b2f6..11d1b89 100644
--- a/display/res.c
+++ b/display/res.c
@@ -769,8 +769,12 @@ void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd)
     EngReleaseSemaphore(pdev->Res->cmd_sem);
 }
 
+QXLPHYSICAL SurfaceToPhysical(PDev *pdev, UINT8 *base_mem)
+{
+    return PA(pdev, base_mem, pdev->vram_mem_slot);
+}
 
-_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT32 *stride,
+_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, INT32 *stride,
                               UINT8 **base_mem, QXLPHYSICAL *phys_mem, UINT8 allocation_type)
 {
     DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
@@ -786,7 +790,7 @@ _inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT
         *stride = x * depth / 8;
         *stride = ALIGN(*stride, 4);
         *base_mem = AllocMem(pdev, MSPACE_TYPE_DEVRAM, (*stride) * y);
-        *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+        *phys_mem = SurfaceToPhysical(pdev, *base_mem);
         break;
     case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
         *stride = x * depth / 8;
@@ -809,7 +813,7 @@ _inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT
 }
 
 void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
-                   UINT32 *stride, UINT8 **base_mem, UINT8 allocation_type)
+                   INT32 *stride, UINT8 **base_mem, UINT8 allocation_type)
 {
     GetSurfaceMemory(pdev, x, y, depth, stride, base_mem, surface_phys, allocation_type);
 }
diff --git a/display/res.h b/display/res.h
index b38d5cf..1feadb0 100644
--- a/display/res.h
+++ b/display/res.h
@@ -31,8 +31,9 @@ void PushDrawable(PDev *pdev, QXLDrawable *drawable);
 QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id);
 void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd);
 
+QXLPHYSICAL SurfaceToPhysical(PDev *pdev, UINT8 *base_mem);
 void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
-                   UINT32 *stride, UINT8 **base_mem, UINT8 allocation_type);
+                   INT32 *stride, UINT8 **base_mem, UINT8 allocation_type);
 void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UINT8 allocation_type);
 void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type);
 BOOL QXLGetPath(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *path_phys, PATHOBJ *path);
diff --git a/display/surface.c b/display/surface.c
index 20fd950..519d613 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -82,69 +82,115 @@ static VOID FreeDrawArea(DrawArea *drawarea)
     }
 }
 
-HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
-                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type)
+static void BitmapFormatToDepthAndSurfaceFormat(ULONG format, UINT32 *depth, UINT32 *surface_format)
 {
-    UINT32 surface_format, depth;
-    HBITMAP surf;
-    UINT32 stride;
-
     switch (format) {
         case BMF_16BPP:
-            surface_format = SPICE_SURFACE_FMT_16_555;
-            depth = 16;
+            *surface_format = SPICE_SURFACE_FMT_16_555;
+            *depth = 16;
             break;
         case BMF_24BPP:
         case BMF_32BPP:
-            surface_format = SPICE_SURFACE_FMT_32_xRGB;
-            depth = 32;
+            *surface_format = SPICE_SURFACE_FMT_32_xRGB;
+            *depth = 32;
             break;
-        case BMF_8BPP:
         default:
-            return 0;
+            *depth = 0;
+            break;
     };
+}
+
+static UINT8 *CreateSurfaceHelper(PDev *pdev, UINT32 surface_id,
+                                  UINT32 cx, UINT32 cy, ULONG format,
+                                  UINT8 allocation_type,
+                                  INT32 *stride, UINT32 *surface_format,
+                                  QXLPHYSICAL *phys_mem)
+{
+    UINT32 depth;
+    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
+    UINT8 *base_mem;
+    int size;
+
+    BitmapFormatToDepthAndSurfaceFormat(format, &depth, surface_format);
+    ASSERT(pdev, depth != 0);
+    ASSERT(pdev, stride);
+    QXLGetSurface(pdev, phys_mem, cx, cy, depth, stride, &base_mem, allocation_type);
+    DEBUG_PRINT((pdev, 3,
+        "%s: %d, pm %0lX, fmt %d, d %d, s (%d, %d) st %d\n",
+        __FUNCTION__, surface_id, (uint64_t)*phys_mem, *surface_format,
+        depth, cx, cy, *stride));
+    size = abs(*stride) * cy;
+    if (!base_mem) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: %d: QXLGetSurface failed (%d bytes alloc)\n",
+            __FUNCTION__, pdev, surface_id, size));
+        return NULL;
+    }
+    if (!CreateDrawArea(pdev, base_mem, surface_info->bitmap_format, cx, cy, *stride, surface_id)) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: CreateDrawArea failed (%d)\n",
+            __FUNCTION__, pdev, surface_id, size));
+        // TODO: Why did it fail? nothing in the MSDN
+        QXLDelSurface(pdev, base_mem, allocation_type);
+        return NULL;
+    }
+    return base_mem;
+}
+
+static void SendSurfaceCreateCommand(PDev *pdev, UINT32 surface_id, SIZEL size,
+                                     UINT32 surface_format, INT32 stride, QXLPHYSICAL phys_mem)
+{
+    QXLSurfaceCmd *surface;
+
+    surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_CREATE, surface_id);
+    surface->u.surface_create.format = surface_format;
+    surface->u.surface_create.width = size.cx;
+    surface->u.surface_create.height = size.cy;
+    surface->u.surface_create.stride = stride;
+    surface->u.surface_create.data = phys_mem;
+    PushSurfaceCmd(pdev, surface);
+}
+
+HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
+                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type)
+{
+    UINT32 surface_format, depth;
+    HBITMAP hbitmap;
+    INT32 stride;
+    SurfaceInfo *surface_info;
 
-    if (!(surf = EngCreateDeviceBitmap((DHSURF)GetSurfaceInfo(pdev, surface_id), size, format))) {
+    DEBUG_PRINT((pdev, 9, "%s: %p: %d, (%dx%d), %d\n", __FUNCTION__, pdev, surface_id,
+                size.cx, size.cy, format));
+    surface_info = GetSurfaceInfo(pdev, surface_id);
+
+    if (!(hbitmap = EngCreateDeviceBitmap((DHSURF)surface_info, size, format))) {
         DEBUG_PRINT((pdev, 0, "%s: EngCreateDeviceBitmap failed, pdev 0x%lx, surface_id=%d\n",
                     __FUNCTION__, pdev, surface_id));
         goto out_error1;
     }
 
-    if (!EngAssociateSurface((HSURF)surf, pdev->eng, QXL_SURFACE_HOOKS)) {
+    if (!EngAssociateSurface((HSURF)hbitmap, pdev->eng, QXL_SURFACE_HOOKS)) {
         DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
         goto out_error2;
     }
-
-    GetSurfaceInfo(pdev, surface_id)->u.pdev = pdev;
-
-    QXLGetSurface(pdev, phys_mem, size.cx, size.cy, depth,
-                  &stride, base_mem, allocation_type);
-    if (!*base_mem) {
+    surface_info->u.pdev = pdev;
+    surface_info->hbitmap = hbitmap;
+    surface_info->copy = NULL;
+    surface_info->size = size;
+    surface_info->bitmap_format = format;
+    if ((*base_mem = CreateSurfaceHelper(pdev, surface_id, size.cx, size.cy, format,
+                                         allocation_type, &stride, &surface_format,
+                                         phys_mem)) == NULL) {
+        DEBUG_PRINT((pdev, 0, "%s: failed, pdev 0x%lx, surface_id=%d\n",
+                    __FUNCTION__, pdev, surface_id));
         goto out_error2;
     }
 
-    if (!CreateDrawArea(pdev, *base_mem, format, size.cx, size.cy, stride, surface_id)) {
-        goto out_error3;
-    }
-
     if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0) {
-        QXLSurfaceCmd *surface;
-
-        surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_CREATE, surface_id);
-        surface->u.surface_create.format = surface_format;
-        surface->u.surface_create.width = size.cx;
-        surface->u.surface_create.height = size.cy;
-        surface->u.surface_create.stride = -(INT32)stride;
-        surface->u.surface_create.data = *phys_mem;
-        PushSurfaceCmd(pdev, surface);
+        SendSurfaceCreateCommand(pdev, surface_id, size, surface_format, -stride, *phys_mem);
     }
 
-    return surf;
-
-out_error3:
-    QXLDelSurface(pdev, *base_mem, allocation_type);
+    return hbitmap;
 out_error2:
-    EngDeleteSurface((HSURF)surf);
+    EngDeleteSurface((HSURF)hbitmap);
 out_error1:
     return 0;
 }
@@ -175,3 +221,147 @@ VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
         }
     }
 }
+
+static void CleanupSurfaceInfo(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
+{
+    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
+
+    FreeDrawArea(&surface_info->draw_area);
+    if (surface_info->draw_area.base_mem != NULL) {
+        QXLDelSurface(pdev, surface_info->draw_area.base_mem, allocation_type);
+    }
+}
+
+BOOL MoveSurfaceToVideoRam(PDev *pdev, UINT32 surface_id)
+{
+    QXLSurfaceCmd *surface;
+    UINT32 surface_format;
+    UINT32 depth;
+    int count_used = 0;
+    int size;
+    INT32 stride = 0;
+    QXLPHYSICAL phys_mem;
+    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
+    UINT32 cx = surface_info->size.cx;
+    UINT32 cy = surface_info->size.cy;
+    UINT8 *base_mem;
+
+    DEBUG_PRINT((pdev, 3, "%s: %d\n", __FUNCTION__, surface_id));
+    if ((base_mem = CreateSurfaceHelper(pdev, surface_id, cx, cy, surface_info->bitmap_format,
+                                        DEVICE_BITMAP_ALLOCATION_TYPE_VRAM,
+                                        &stride, &surface_format, &phys_mem)) == NULL) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: %d: failed\n", __FUNCTION__, pdev, surface_id));
+        return FALSE;
+    }
+    size = abs(stride) * cy;
+    if (!EngModifySurface((HSURF)surface_info->hbitmap, pdev->eng, QXL_SURFACE_HOOKS,
+        MS_NOTSYSTEMMEMORY, (DHSURF)surface_info, NULL, 0, NULL)) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: %d: EngModifySurface failed\n",
+            __FUNCTION__, pdev, surface_id));
+        CleanupSurfaceInfo(pdev, surface_id, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+        return FALSE;
+    }
+    DEBUG_PRINT((pdev, 3, "%s: stride = %d, phys_mem = %0lX, base_mem = %p\n",
+        __FUNCTION__, -stride, (uint64_t)phys_mem, base_mem));
+    DEBUG_PRINT((pdev, 3, "%s: copy %d bytes to %d\n", __FUNCTION__, size, surface_id));
+    // Everything allocated, nothing can fail (API wise) from this point
+    RtlCopyMemory(base_mem, surface_info->copy, size);
+    EngFreeMem(surface_info->copy);
+    surface_info->copy = NULL;
+    SendSurfaceCreateCommand(pdev, surface_id, surface_info->size, surface_format,
+                             -stride, phys_mem);
+    return TRUE;
+}
+
+/* when we return from S3 we need to resend all the surface creation commands.
+ * Actually moving the memory vram<->guest is not strictly neccessary since vram
+ * is not reset during the suspend, so contents are not lost */
+int MoveAllSurfacesToVideoRam(PDev *pdev)
+{
+    UINT32 surface_id;
+    SurfaceInfo *surface_info;
+
+    /* brute force implementation - alternative is to keep an updated used_surfaces list */
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+
+    for (surface_id = 1 ; surface_id < pdev->n_surfaces ; ++surface_id) {
+        surface_info = GetSurfaceInfo(pdev, surface_id);
+        if (!surface_info->draw_area.base_mem) {
+            continue;
+        }
+        if (surface_info->u.pdev != pdev) {
+            DEBUG_PRINT((pdev, 3, "%s: %p: not our pdev (%p)\n", __FUNCTION__, pdev,
+                         surface_info->u.pdev));
+            continue;
+        }
+        if (surface_info->draw_area.surf_obj) {
+            DEBUG_PRINT((pdev, 3, "%s: surface_id = %d, surf_obj not empty\n", __FUNCTION__,
+                         surface_id));
+            continue;
+        }
+        if (surface_info->copy == NULL) {
+            DEBUG_PRINT((pdev, 3, "%s: %p: %d: no copy buffer, ignored\n", __FUNCTION__,
+                         pdev, surface_id));
+        }
+        if (!MoveSurfaceToVideoRam(pdev, surface_id)) {
+            /* Some of the surfaces have not been moved to video ram.
+             * they will remain managed by GDI. */
+            DEBUG_PRINT((pdev, 0, "%s: %p: %d: failed moving to vram\n", __FUNCTION__,
+                         pdev, surface_id));
+        }
+    }
+    return TRUE;
+}
+
+BOOL MoveAllSurfacesToRam(PDev *pdev)
+{
+    UINT32 surface_id;
+    SurfaceInfo *surface_info;
+    SURFOBJ *surf_obj;
+    UINT8 *copy;
+    UINT8 *line0;
+    int size;
+    QXLPHYSICAL phys_mem;
+
+    for (surface_id = 1 ; surface_id < pdev->n_surfaces ; ++surface_id) {
+        surface_info = GetSurfaceInfo(pdev, surface_id);
+        if (!surface_info->draw_area.base_mem) {
+            continue;
+        }
+        surf_obj = surface_info->draw_area.surf_obj;
+        if (!surf_obj) {
+            DEBUG_PRINT((pdev, 3, "%s: %d: no surfobj, not copying\n", __FUNCTION__, surface_id));
+            continue;
+        }
+        size = surf_obj->sizlBitmap.cy * abs(surf_obj->lDelta);
+        copy = EngAllocMem(0, size, ALLOC_TAG);
+        DEBUG_PRINT((pdev, 3, "%s: %d: copying #%d to %p (%d)\n", __FUNCTION__, surface_id, size,
+            copy, surf_obj->lDelta));
+        RtlCopyMemory(copy, surface_info->draw_area.base_mem, size);
+        surface_info->copy = copy;
+        line0 = surf_obj->lDelta > 0 ? copy : copy + abs(surf_obj->lDelta) *
+                (surf_obj->sizlBitmap.cy - 1);
+        if (!EngModifySurface((HSURF)surface_info->hbitmap,
+                      pdev->eng,
+                      0, /* from the example: used to monitor memory HOOK_COPYBITS | HOOK_BITBLT, */
+                      0,                    /* It's system-memory */
+                      (DHSURF)surface_info,
+                      line0,
+                      surf_obj->lDelta,
+                      NULL)) {
+            /* Send a create messsage for this surface - we previously did a destroy all. */
+            EngFreeMem(surface_info->copy);
+            surface_info->copy = NULL;
+            DEBUG_PRINT((pdev, 0, "%s: %d: EngModifySurface failed, sending create\n",
+                         __FUNCTION__, surface_id));
+            phys_mem = SurfaceToPhysical(pdev, surface_info->draw_area.base_mem);
+            SendSurfaceCreateCommand(pdev, surface_id, surf_obj->sizlBitmap,
+                                     surface_info->bitmap_format, -surf_obj->lDelta, phys_mem);
+            return FALSE;
+        }
+        QXLDelSurface(pdev, surface_info->draw_area.base_mem, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+        surface_info->draw_area.base_mem = copy;
+        FreeDrawArea(&surface_info->draw_area);
+    }
+    return TRUE;
+}
diff --git a/display/surface.h b/display/surface.h
index f723392..d770884 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -105,4 +105,7 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
                            UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type);
 VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type);
 
+int MoveAllSurfacesToVideoRam(PDev *pdev);
+BOOL MoveAllSurfacesToRam(PDev *pdev);
+
 #endif
-- 
1.7.6



More information about the Spice-devel mailing list