summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Levy <alevy@redhat.com>2011-06-05 16:45:03 +0300
committerAlon Levy <alevy@redhat.com>2011-07-31 12:34:29 +0300
commit9cbe84d0843fff005d4f62b41878a8f51130998c (patch)
tree3d9e955a93fc7d5b025c1a0b70cc56ab220fe642
parent6f7262628021333748e823a3b2219a7722fd405e (diff)
display/surface: add surfaces from/to ram
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@redhat.com>
-rw-r--r--display/driver.c4
-rw-r--r--display/qxldd.h6
-rw-r--r--display/res.c10
-rw-r--r--display/res.h3
-rw-r--r--display/surface.c266
-rw-r--r--display/surface.h3
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 eda6663..00f7f21 100644
--- a/display/res.c
+++ b/display/res.c
@@ -771,8 +771,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__));
@@ -794,7 +798,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_VRAM, (*stride) * y, FALSE);
- *phys_mem = PA(pdev, (PVOID)((UINT64)*base_mem), pdev->vram_mem_slot);
+ *phys_mem = SurfaceToPhysical(pdev, *base_mem);
break;
case DEVICE_BITMAP_ALLOCATION_TYPE_RAM:
/* used only before suspend to sleep (DrvAssertMode(FALSE)) and then released
@@ -811,7 +815,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