summaryrefslogtreecommitdiff
path: root/xddm/display/surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'xddm/display/surface.c')
-rw-r--r--xddm/display/surface.c407
1 files changed, 407 insertions, 0 deletions
diff --git a/xddm/display/surface.c b/xddm/display/surface.c
new file mode 100644
index 0000000..2cc5895
--- /dev/null
+++ b/xddm/display/surface.c
@@ -0,0 +1,407 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This software is licensed under the GNU General Public License,
+ version 2 (GPLv2) (see COPYING for details), subject to the
+ following clarification.
+
+ With respect to binaries built using the Microsoft(R) Windows
+ Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+ derived from the WDK ("WDK Code"). As to WDK Code, by using or
+ distributing such binaries you agree to be bound by the Microsoft
+ Software License Terms for the WDK. All WDK Code is considered by
+ the GPLv2 licensors to qualify for the special exception stated in
+ section 3 of GPLv2 (commonly known as the system library
+ exception).
+
+ There is NO WARRANTY for this software, express or implied,
+ including the implied warranties of NON-INFRINGEMENT, TITLE,
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "stddef.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "os_dep.h"
+
+#include "winerror.h"
+#include "windef.h"
+#include "wingdi.h"
+#include "winddi.h"
+#include "devioctl.h"
+#include "ntddvdeo.h"
+
+#include "qxldd.h"
+#include "utils.h"
+#include "mspace.h"
+#include "res.h"
+#include "surface.h"
+
+static BOOL CreateDrawArea(PDev *pdev, UINT8 *base_mem, ULONG format, UINT32 cx, UINT32 cy,
+ UINT32 stride, UINT32 surface_id)
+{
+ SIZEL size;
+ DrawArea *drawarea;
+
+ size.cx = cx;
+ size.cy = cy;
+
+ drawarea = &GetSurfaceInfo(pdev, surface_id)->draw_area;
+
+ if (!(drawarea->bitmap = (HSURF)EngCreateBitmap(size, stride, format, 0, base_mem))) {
+ DEBUG_PRINT((pdev, 0, "%s: EngCreateBitmap failed\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ if (!EngAssociateSurface(drawarea->bitmap, pdev->eng, 0)) {
+ DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
+ goto error;
+ }
+
+ if (!(drawarea->surf_obj = EngLockSurface(drawarea->bitmap))) {
+ DEBUG_PRINT((pdev, 0, "%s: EngLockSurface failed\n", __FUNCTION__));
+ goto error;
+ }
+
+ drawarea->base_mem = base_mem;
+
+ return TRUE;
+error:
+ EngDeleteSurface(drawarea->bitmap);
+ return FALSE;
+}
+
+static VOID FreeDrawArea(DrawArea *drawarea)
+{
+ if (drawarea->surf_obj) {
+ EngUnlockSurface(drawarea->surf_obj);
+ EngDeleteSurface(drawarea->bitmap);
+ drawarea->surf_obj = NULL;
+ }
+}
+
+static void BitmapFormatToDepthAndSurfaceFormat(ULONG format, UINT32 *depth, UINT32 *surface_format)
+{
+ switch (format) {
+ case BMF_16BPP:
+ *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;
+ break;
+ default:
+ *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,
+ int keep_data)
+{
+ QXLSurfaceCmd *surface;
+
+ surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_CREATE, surface_id);
+ if (keep_data) {
+ surface->flags |= QXL_SURF_FLAG_KEEP_DATA;
+ }
+ 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;
+
+ 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)hbitmap, pdev->eng, QXL_SURFACE_HOOKS)) {
+ DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
+ goto out_error2;
+ }
+ 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;
+ }
+ surface_info->stride = stride;
+ if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0) {
+ SendSurfaceCreateCommand(pdev, surface_id, size, surface_format, -stride, *phys_mem, 0);
+ }
+
+ return hbitmap;
+out_error2:
+ EngDeleteSurface((HSURF)hbitmap);
+out_error1:
+ return 0;
+}
+
+VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
+{
+ DrawArea *drawarea;
+
+ drawarea = &GetSurfaceInfo(pdev,surface_id)->draw_area;
+
+ FreeDrawArea(drawarea);
+
+ if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0 &&
+ pdev->surfaces_info[surface_id].draw_area.base_mem != NULL) {
+
+ if (allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_RAM) {
+ /* server side this surface is already destroyed, just free it here */
+ ASSERT(pdev, pdev->surfaces_info[surface_id].draw_area.base_mem ==
+ pdev->surfaces_info[surface_id].copy);
+ QXLDelSurface(pdev,
+ pdev->surfaces_info[surface_id].draw_area.base_mem,
+ allocation_type);
+ FreeSurfaceInfo(pdev, surface_id);
+ } else {
+ QXLSurfaceCmd *surface_cmd;
+ surface_cmd = SurfaceCmd(pdev, QXL_SURFACE_CMD_DESTROY, surface_id);
+ QXLGetDelSurface(pdev, surface_cmd, surface_id, allocation_type);
+ PushSurfaceCmd(pdev, surface_cmd);
+ }
+ }
+}
+
+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, 1);
+ 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 %p\n", __FUNCTION__, pdev));
+
+ 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));
+ continue;
+ }
+ 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;
+}
+
+/* to_surface_id is exclusive */
+static void SendSurfaceRangeCreateCommand(PDev *pdev, UINT32 from_surface_id, UINT32 to_surface_id)
+{
+ UINT32 surface_id;
+
+ ASSERT(pdev, from_surface_id < to_surface_id);
+ ASSERT(pdev, to_surface_id <= pdev->n_surfaces);
+
+ for (surface_id = from_surface_id; surface_id < to_surface_id; surface_id++) {
+ SurfaceInfo *surface_info;
+ SURFOBJ *surf_obj;
+ QXLPHYSICAL phys_mem;
+ UINT32 surface_format;
+ UINT32 depth;
+
+ 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) {
+ continue;
+ }
+
+ phys_mem = SurfaceToPhysical(pdev, surface_info->draw_area.base_mem);
+ BitmapFormatToDepthAndSurfaceFormat(surface_info->bitmap_format, &depth, &surface_format);
+
+ SendSurfaceCreateCommand(pdev, surface_id, surf_obj->sizlBitmap,
+ surface_format, -surface_info->stride, phys_mem,
+ /* the surface is still there, tell server not to erase */
+ 1);
+ }
+}
+
+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 for %d-%d\n",
+ __FUNCTION__, surface_id, surface_id, pdev->n_surfaces - 1));
+ SendSurfaceRangeCreateCommand(pdev, surface_id, pdev->n_surfaces);
+ 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;
+}