summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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