[Spice-commits] display/brush.c display/dd.c display/dd.h display/driver.c display/qxldd.h display/res.c display/res.h display/rop.c display/sources display/surface.c display/surface.h display/text.c display/utils.h include/qxl_driver.h miniport/qxl.c

Izik Eidus izik at kemper.freedesktop.org
Fri Apr 2 19:47:16 PDT 2010


 display/brush.c      |   13 +
 display/dd.c         |  122 ++++++++++++++++
 display/dd.h         |   15 ++
 display/driver.c     |  175 ++++++++++++++++++++---
 display/qxldd.h      |   35 ++++
 display/res.c        |  249 ++++++++++++++++++++++++++++++---
 display/res.h        |   22 +-
 display/rop.c        |  379 ++++++++++++++++++++++++++++++++++-----------------
 display/sources      |    1 
 display/surface.c    |   65 +++++++-
 display/surface.h    |   50 +++++-
 display/text.c       |   12 +
 display/utils.h      |    6 
 include/qxl_driver.h |   11 +
 miniport/qxl.c       |   12 +
 15 files changed, 969 insertions(+), 198 deletions(-)

New commits:
commit f7540a4bbd89b25f2b5e9d30635897757ad52c04
Author: Izik Eidus <ieidus at redhat.com>
Date:   Wed Mar 31 01:47:12 2010 +0300

    qxl driver: add off screen supprot
    
    Signed-off-by: Izik Eidus <ieidus at redhat.com>

diff --git a/display/brush.c b/display/brush.c
index 802c0a9..d69cb76 100644
--- a/display/brush.c
+++ b/display/brush.c
@@ -315,7 +315,8 @@ BOOL APIENTRY DrvRealizeBrush(BRUSHOBJ *brush, SURFOBJ *target, SURFOBJ *pattern
 
 
 static _inline BOOL GetPattern(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *pattern,
-                               InternalBrush *brush)
+                               InternalBrush *brush, INT32 *surface_dest,
+                               SpiceRect *surface_rect)
 {
     HSURF hsurf;
     SURFOBJ *surf_obj;
@@ -342,7 +343,9 @@ static _inline BOOL GetPattern(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *p
     area.right = brush->size.cx;
     area.bottom = brush->size.cy;
 
-    if (!QXLGetBitmap(pdev, drawable, pattern, surf_obj, &area, NULL, &key, TRUE)) {
+    CopyRect(surface_rect, &area);
+
+    if (!QXLGetBitmap(pdev, drawable, pattern, surf_obj, &area, NULL, &key, TRUE, surface_dest)) {
         goto error_2;
     }
 
@@ -361,7 +364,8 @@ error_1:
 
 
 BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, SpiceBrush *qxl_brush,
-                            BRUSHOBJ *brush, POINTL *brush_pos)
+                 BRUSHOBJ *brush, POINTL *brush_pos, INT32 *surface_dest,
+                 SpiceRect *surface_rect)
 {
     DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
     ASSERT(pdev, brush);
@@ -377,7 +381,8 @@ BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, SpiceBrush *qxl_brush,
         qxl_brush->type = SPICE_BRUSH_TYPE_PATTERN;
         qxl_brush->u.pattern.pos.x = brush_pos->x;
         qxl_brush->u.pattern.pos.y = brush_pos->y;
-        if (!GetPattern(pdev, drawable, &qxl_brush->u.pattern.pat, brush->pvRbrush)) {
+        if (!GetPattern(pdev, drawable, &qxl_brush->u.pattern.pat, brush->pvRbrush,
+                        surface_dest, surface_rect)) {
             return FALSE;
         }
     } else {
diff --git a/display/dd.c b/display/dd.c
new file mode 100644
index 0000000..211a4fb
--- /dev/null
+++ b/display/dd.c
@@ -0,0 +1,122 @@
+#include <ddrawi.h>
+#include <ddraw.h>
+#include <dxmini.h>
+#include "os_dep.h"
+#include "devioctl.h"
+#include "ntddvdeo.h"
+#include "ioaccess.h"
+#include "qxldd.h"
+
+static UINT8 get_depth(PDev *pdev)
+{
+    if (pdev->bitmap_format == BMF_32BPP) {
+        return 32;
+    } else {
+        return 16;
+    }
+}
+
+BOOL DrvGetDirectDrawInfo(DHPDEV dhpdev, DD_HALINFO *pHallInfo,
+                          DWORD *pdvNumHeaps, VIDEOMEMORY *pvmList,
+                          DWORD *pdvNumFourCCCodes,
+                          DWORD *pdvFourCC)
+{
+    PDev *pdev;
+    DWORD offset;
+
+    pdev = (PDev *)dhpdev;
+
+    *pdvNumHeaps = 1;
+    *pdvNumFourCCCodes = 0;
+
+    if (!pdev->dd_slot_initialized) {
+        return FALSE;
+    }
+
+    offset = pdev->resolution.cy * pdev->stride;
+
+    if (pvmList) {
+        VIDEOMEMORY *pvmobj = pvmList;
+
+        pvmobj->dwFlags = VIDMEM_ISLINEAR;
+
+        pvmobj->fpStart = (FLATPTR)pdev->fb;
+        pvmobj->fpEnd = pvmobj->fpStart + pdev->fb_size - 1;
+
+        pvmobj->ddsCaps.dwCaps = 0;
+        pvmobj->ddsCapsAlt.dwCaps = 0;
+
+        pdev->pvmList = pvmList;
+    }
+
+    memset(pHallInfo, 0, sizeof(DD_HALINFO));
+
+    pHallInfo->vmiData.pvPrimary =  pdev->fb;
+    pHallInfo->vmiData.fpPrimary = 0;
+
+    pHallInfo->dwSize = sizeof (DD_HALINFO);
+
+    pHallInfo->vmiData.dwFlags = 0;
+    pHallInfo->vmiData.dwDisplayWidth = pdev->resolution.cx;
+    pHallInfo->vmiData.dwDisplayHeight = pdev->resolution.cy;
+    pHallInfo->vmiData.lDisplayPitch = pdev->stride;
+    pHallInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
+    pHallInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
+
+    pHallInfo->vmiData.ddpfDisplay.dwRGBBitCount = get_depth(pdev);
+
+    pHallInfo->vmiData.ddpfDisplay.dwRBitMask = pdev->red_mask;
+    pHallInfo->vmiData.ddpfDisplay.dwGBitMask = pdev->green_mask;
+    pHallInfo->vmiData.ddpfDisplay.dwBBitMask = pdev->blue_mask;
+
+    pHallInfo->vmiData.dwOffscreenAlign = 4;
+    pHallInfo->vmiData.dwOverlayAlign = 4;
+    pHallInfo->vmiData.dwTextureAlign = 4;
+    pHallInfo->vmiData.dwZBufferAlign = 4;
+    pHallInfo->vmiData.dwAlphaAlign = 4;
+
+    pHallInfo->ddCaps.dwSize = sizeof (DDCORECAPS);
+    pHallInfo->ddCaps.dwVidMemTotal = pdev->fb_size;
+    pHallInfo->ddCaps.dwVidMemFree = pdev->fb_size;
+
+    pdev->dd_initialized = TRUE;
+
+    return TRUE;
+}
+
+DWORD CALLBACK QxlCanCreateSurface(PDD_CANCREATESURFACEDATA data)
+{
+    return DDHAL_DRIVER_NOTHANDLED;
+}
+
+DWORD CALLBACK QxlFlip(PDD_FLIPDATA lpFlip)
+{
+    return DDHAL_DRIVER_NOTHANDLED;
+}
+
+BOOL DrvEnableDirectDraw(DHPDEV dhpdev, DD_CALLBACKS *pCallBacks,
+                         DD_SURFACECALLBACKS *pSurfaceCallBacks,
+                         DD_PALETTECALLBACKS *pPaletteCallBacks)
+{
+    memset(pCallBacks, 0, sizeof (DD_CALLBACKS));
+    memset(pSurfaceCallBacks, 0, sizeof (DD_SURFACECALLBACKS));
+    memset(pPaletteCallBacks, 0, sizeof (DD_PALETTECALLBACKS));
+
+    pCallBacks->dwSize = sizeof (DD_CALLBACKS);
+    pCallBacks->CanCreateSurface = QxlCanCreateSurface;
+
+    pSurfaceCallBacks->dwSize = sizeof (DD_SURFACECALLBACKS);
+    pSurfaceCallBacks->Flip = QxlFlip;
+
+    pPaletteCallBacks->dwSize = sizeof (DD_PALETTECALLBACKS);
+
+    return TRUE;
+}
+
+void DrvDisableDirectDraw(DHPDEV dhpdev)
+{
+    PDev *pdev;
+
+    pdev = (PDev *)dhpdev;
+    pdev->dd_initialized = FALSE;
+}
diff --git a/display/dd.h b/display/dd.h
new file mode 100644
index 0000000..ffcd8e1
--- /dev/null
+++ b/display/dd.h
@@ -0,0 +1,15 @@
+#ifndef DD_H
+#define DD_H
+
+BOOL DrvGetDirectDrawInfo(DHPDEV dhpdev, DD_HALINFO *pHallInfo,
+                          DWORD *pdvNumHeaps, VIDEOMEMORY *pvmList,
+                          DWORD *pdvNumFourCCCodes,
+                          DWORD *pdvFourCC);
+
+BOOL DrvEnableDirectDraw(DHPDEV dhpdev, DD_CALLBACKS *pCallBacks,
+                         DD_SURFACECALLBACKS *pSurfaceCallBacks,
+                         DD_PALETTECALLBACKS *pPaletteCallBacks);
+
+void DrvDisableDirectDraw(DHPDEV dhpdev);
+
+#endif
diff --git a/display/driver.c b/display/driver.c
index d3737e3..321d6fe 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -35,6 +35,7 @@
 #include "mspace.h"
 #include "res.h"
 #include "surface.h"
+#include "dd.h"
 
 #define DEVICE_NAME L"qxldd"
 
@@ -61,6 +62,12 @@ static DRVFN drv_calls[] = {
     {INDEX_DrvStretchBltROP, (PFN)DrvStretchBltROP},
     {INDEX_DrvTransparentBlt, (PFN)DrvTransparentBlt},
     {INDEX_DrvAlphaBlend, (PFN)DrvAlphaBlend},
+    {INDEX_DrvCreateDeviceBitmap, (PFN)DrvCreateDeviceBitmap},
+    {INDEX_DrvDeleteDeviceBitmap, (PFN)DrvDeleteDeviceBitmap},
+
+    {INDEX_DrvGetDirectDrawInfo, (PFN)DrvGetDirectDrawInfo},
+    {INDEX_DrvEnableDirectDraw, (PFN)DrvEnableDirectDraw},
+    {INDEX_DrvDisableDirectDraw, (PFN)DrvDisableDirectDraw},
 
 #ifdef CALL_TEST
     {INDEX_DrvFillPath, (PFN)DrvFillPath},
@@ -512,9 +519,14 @@ DHPDEV DrvEnablePDEV(DEVMODEW *dev_mode, PWSTR ignore1, ULONG ignore2, HSURF *ig
         goto err3;
     }
 
+    if (!(pdev->cmd_sem = EngCreateSemaphore())) {
+        DEBUG_PRINT((NULL, 0, "%s: create cmd sem failed\n", __FUNCTION__));
+        goto err4;
+    }
+
     if (!ResInit(pdev)) {
         DEBUG_PRINT((NULL, 0, "%s: init res failed\n", __FUNCTION__));
-        goto err4;
+        goto err5;
     }
 
     RtlCopyMemory(dev_caps, &gdi_info, dev_caps_size);
@@ -523,6 +535,8 @@ DHPDEV DrvEnablePDEV(DEVMODEW *dev_mode, PWSTR ignore1, ULONG ignore2, HSURF *ig
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
     return(DHPDEV)pdev;
 
+err5:
+    EngDeleteSemaphore(pdev->cmd_sem);
 err4:
     EngDeleteSemaphore(pdev->print_sem);
 
@@ -543,8 +557,10 @@ VOID DrvDisablePDEV(DHPDEV in_pdev)
     PDev* pdev = (PDev*)in_pdev;
 
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    EngFreeMem(pdev->surfaces_info);
     ResDestroy(pdev);
     DestroyPalette(pdev);
+    EngDeleteSemaphore(pdev->cmd_sem);
     EngDeleteSemaphore(pdev->malloc_sem);
     EngDeleteSemaphore(pdev->print_sem);
     EngFreeMem(pdev);
@@ -591,6 +607,12 @@ static void DestroyPrimarySurface(PDev *pdev)
     WRITE_PORT_UCHAR(pdev->destroy_primary_port, 0);
 }
 
+static void DestroyAllSurfaces(PDev *pdev)
+{
+    HideMouse(pdev);
+    WRITE_PORT_UCHAR(pdev->destroy_all_surfaces_port, 0);
+}
+
 BOOL SetHardwareMode(PDev *pdev)
 {
     VIDEO_MODE_INFORMATION video_info;
@@ -624,6 +646,49 @@ static VOID UpdateMainSlot(PDev *pdev, MemSlot *slot)
     pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
 }
 
+static void RemoveVRamSlot(PDev *pdev)
+{
+    WRITE_PORT_UCHAR(pdev->memslot_del_port, pdev->dd_mem_slot);
+    pdev->dd_slot_initialized = FALSE;
+}
+
+static BOOLEAN CreateVRamSlot(PDev *pdev)
+{
+    QXLMemSlot *slot;
+    UINT64 high_bits;
+    UINT8 slot_id = pdev->main_mem_slot + 1;
+
+    if (slot_id >= pdev->num_mem_slot) {
+        return FALSE;
+    }
+
+    pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
+
+
+    *pdev->ram_slot_start = pdev->fb_phys;
+    *pdev->ram_slot_end = pdev->fb_phys + pdev->fb_size;
+
+    WRITE_PORT_UCHAR(pdev->memslot_add_port, slot_id);
+
+    pdev->dd_mem_slot = slot_id;
+
+    pdev->mem_slots[slot_id].slot.generation = *pdev->slots_generation;
+    pdev->mem_slots[slot_id].slot.start_phys_addr = pdev->fb_phys;
+    pdev->mem_slots[slot_id].slot.end_phys_addr = pdev->fb_phys + pdev->fb_size;
+    pdev->mem_slots[slot_id].slot.start_virt_addr = (UINT64)pdev->fb;
+    pdev->mem_slots[slot_id].slot.end_virt_addr = (UINT64)pdev->fb + pdev->fb_size;
+
+    high_bits = slot_id << pdev->slot_gen_bits;
+    high_bits |= pdev->mem_slots[slot_id].slot.generation;
+    high_bits <<= (64 - (pdev->slot_gen_bits + pdev->slot_id_bits));
+    pdev->mem_slots[slot_id].high_bits = high_bits;
+
+    pdev->dd_slot_initialized = TRUE;
+
+    return TRUE;
+}
+
+
 BOOL PrepareHardware(PDev *pdev)
 {
     VIDEO_MEMORY video_mem;
@@ -671,6 +736,7 @@ BOOL PrepareHardware(PDev *pdev)
 
     pdev->update_area_port = dev_info.update_area_port;
     pdev->update_area = dev_info.update_area;
+    pdev->update_surface = dev_info.update_surface;
 
     pdev->mm_clock = dev_info.mm_clock;
 
@@ -680,6 +746,14 @@ BOOL PrepareHardware(PDev *pdev)
     pdev->log_buf = dev_info.log_buf;
     pdev->log_level = dev_info.log_level;
 
+    pdev->n_surfaces = dev_info.n_surfaces;
+    if (!(pdev->surfaces_info = (SurfaceInfo *)EngAllocMem(FL_ZERO_MEMORY,
+                                                           sizeof(SurfaceInfo) *
+                                                           pdev->n_surfaces, ALLOC_TAG))) {
+        DEBUG_PRINT((NULL, 0, "%s: surfaces_info alloc failed\n", __FUNCTION__));
+        return FALSE;
+    }
+
     pdev->mem_slots = EngAllocMem(FL_ZERO_MEMORY, sizeof(PMemSlot) * dev_info.num_mem_slot,
                                   ALLOC_TAG);
     if (!pdev->mem_slots) {
@@ -687,6 +761,9 @@ BOOL PrepareHardware(PDev *pdev)
         return FALSE;
     }
 
+    pdev->slots_generation = dev_info.slots_generation;
+    pdev->ram_slot_start = dev_info.ram_slot_start;
+    pdev->ram_slot_end = dev_info.ram_slot_end;
     pdev->slot_id_bits = dev_info.slot_id_bits;
     pdev->slot_gen_bits = dev_info.slot_gen_bits;
     pdev->main_mem_slot = dev_info.main_mem_slot_id;
@@ -706,8 +783,13 @@ BOOL PrepareHardware(PDev *pdev)
                  video_mem_Info.FrameBufferBase, video_mem_Info.FrameBufferLength));
     pdev->fb = (BYTE*)video_mem_Info.FrameBufferBase;
     pdev->fb_size = video_mem_Info.FrameBufferLength;
+    pdev->fb_phys = dev_info.fb_phys;
 
     pdev->destroy_surface_wait_port = dev_info.destroy_surface_wait_port;
+    pdev->destroy_all_surfaces_port = dev_info.destroy_all_surfaces_port;
+    pdev->memslot_add_port = dev_info.memslot_add_port;
+    pdev->memslot_del_port = dev_info.memslot_del_port;
+
     pdev->create_primary_port = dev_info.create_primary_port;
     pdev->destroy_primary_port = dev_info.destroy_primary_port;
 
@@ -718,6 +800,10 @@ BOOL PrepareHardware(PDev *pdev)
 
     pdev->dev_id = dev_info.dev_id;
 
+    pdev->dd_initialized = FALSE;
+
+    CreateVRamSlot(pdev);
+
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit: 0x%lx %ul\n", __FUNCTION__, pdev,
                  pdev->fb, pdev->fb_size));
     return TRUE;
@@ -746,7 +832,7 @@ static VOID UnmapFB(PDev *pdev)
     }
 }
 
-VOID EnableQXLSurface(PDev *pdev)
+VOID EnableQXLPrimarySurface(PDev *pdev)
 {
     UINT32 depth;
 
@@ -777,7 +863,6 @@ HSURF DrvEnableSurface(DHPDEV in_pdev)
     DWORD length;
     QXLPHYSICAL phys_mem;
     UINT8 *base_mem;
-    DrawArea drawarea;
 
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, in_pdev));
 
@@ -788,19 +873,12 @@ HSURF DrvEnableSurface(DHPDEV in_pdev)
     InitResources(pdev);
 
     if (!(surf = (HSURF)CreateDeviceBitmap(pdev, pdev->resolution, pdev->bitmap_format, &phys_mem,
-                                           &base_mem, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0))) {
+                                           &base_mem, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0))) {
         DEBUG_PRINT((NULL, 0, "%s: create device surface failed, 0x%lx\n",
                      __FUNCTION__, pdev));
         goto err;
     }
 
-    if (!CreateDrawArea(pdev, &drawarea, base_mem, pdev->resolution.cx, pdev->resolution.cy)) {
-        goto err;
-    }
-
-    pdev->draw_bitmap = drawarea.bitmap;
-    pdev->draw_surf = drawarea.surf_obj;
-
     DEBUG_PRINT((NULL, 1, "%s: EngModifySurface(0x%lx, 0x%lx, 0, MS_NOTSYSTEMMEMORY, "
                  "0x%lx, 0x%lx, %lu, NULL)\n",
                  __FUNCTION__,
@@ -814,7 +892,7 @@ HSURF DrvEnableSurface(DHPDEV in_pdev)
     pdev->surf_phys = phys_mem;
     pdev->surf_base = base_mem;
 
-    EnableQXLSurface(pdev);
+    EnableQXLPrimarySurface(pdev);
 
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
     return surf;
@@ -825,7 +903,7 @@ err:
     return NULL;
 }
 
-VOID DisableQXLSurface(PDev *pdev)
+VOID DisableQXLPrimarySurface(PDev *pdev)
 {
     DrawArea drawarea;
 
@@ -836,6 +914,11 @@ VOID DisableQXLSurface(PDev *pdev)
     }
 }
 
+VOID DisableQXLAllSurfaces(PDev *pdev)
+{
+    DestroyAllSurfaces(pdev);
+}
+
 VOID DrvDisableSurface(DHPDEV in_pdev)
 {
     PDev *pdev = (PDev*)in_pdev;
@@ -843,12 +926,13 @@ VOID DrvDisableSurface(DHPDEV in_pdev)
 
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
 
-    DisableQXLSurface(pdev);
+    DisableQXLPrimarySurface(pdev);
+    //DisableQXLAllSurfaces(pdev);
 
     UnmapFB(pdev);
 
     if (pdev->surf) {
-        DeleteDeviceBitmap(pdev->surf);
+        DeleteDeviceBitmap(pdev, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
         pdev->surf = NULL;
     }
 
@@ -860,6 +944,11 @@ VOID DrvDisableSurface(DHPDEV in_pdev)
         pdev->draw_bitmap = NULL;
     }
 
+    if (pdev->surfaces_info) {
+        EngFreeMem(pdev->surfaces_info);
+        pdev->surfaces_info = NULL;
+    }
+
     if (pdev->mem_slots) {
         EngFreeMem(pdev->mem_slots);
         pdev->mem_slots = NULL;
@@ -875,9 +964,11 @@ BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
     if (enable) {
         InitResources(pdev);
-        EnableQXLSurface(pdev);
+        EnableQXLPrimarySurface(pdev);
+        CreateVRamSlot(pdev);
     } else {
-        DisableQXLSurface(pdev);
+        DisableQXLPrimarySurface(pdev);
+        RemoveVRamSlot(pdev);
     }
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit TRUE\n", __FUNCTION__, pdev));
     return TRUE;
@@ -1217,7 +1308,7 @@ BOOL APIENTRY DrvStrokePath(SURFOBJ *surf, PATHOBJ *path, CLIPOBJ *clip, XFORMOB
         }
     }
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_STROKE, &area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_STROKE, &area, clip, GetSurfaceId(surf)))) {
         return FALSE;
     }
 
@@ -1226,7 +1317,8 @@ BOOL APIENTRY DrvStrokePath(SURFOBJ *surf, PATHOBJ *path, CLIPOBJ *clip, XFORMOB
 
     if (!((fore_rop->flags | back_rop->flags) & ROP3_BRUSH)) {
         drawable->u.stroke.brush.type = SPICE_BRUSH_TYPE_NONE;
-    } else if (!QXLGetBrush(pdev, drawable, &drawable->u.stroke.brush, brush, brush_pos)) {
+    } else if (!QXLGetBrush(pdev, drawable, &drawable->u.stroke.brush, brush, brush_pos,
+                            &drawable->surfaces_dest[0], &drawable->surfaces_rects[0])) {
         goto err;
     }
 
@@ -1266,6 +1358,51 @@ err:
     return FALSE;
 }
 
+HBITMAP APIENTRY DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL size, ULONG format)
+{
+    PDev *pdev;
+    UINT8 *base_mem;
+    UINT32 surface_id;
+    QXLPHYSICAL phys_mem;
+    HBITMAP hbitmap;
+
+    pdev = (PDev *)dhpdev;
+
+    if (!pdev->dd_initialized) {
+        return 0;
+    }
+
+    surface_id = GetFreeSurface(pdev);
+    if (!surface_id) {
+        goto out_error;
+    }
+
+    hbitmap = CreateDeviceBitmap(pdev, size, pdev->bitmap_format, &phys_mem, &base_mem, surface_id,
+                                 DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+    if (!hbitmap) {
+        goto out_error;
+    }
+
+    return hbitmap;
+
+    // to optimize the failure case
+out_error:
+	return 0; 
+}
+
+VOID APIENTRY DrvDeleteDeviceBitmap(DHSURF dhsurf)
+{
+    UINT32 surface_id;
+    PDev *pdev;
+    SurfaceInfo *surface;
+
+    surface = (SurfaceInfo *)dhsurf;
+    pdev = surface->pdev;
+    surface_id = surface - pdev->surfaces_info;
+
+    DeleteDeviceBitmap(pdev, surface_id, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+}
+
 #ifdef CALL_TEST
 
 void CountCall(PDev *pdev, int counter)
diff --git a/display/qxldd.h b/display/qxldd.h
index 80dd30a..f1623d1 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -166,6 +166,8 @@ typedef struct DevRes {
     struct InternalPalette *palette_cache[PALETTE_HASH_SIZE];
     UINT32 num_palettes;
 
+    UINT8 *surfaces_used;
+
 #ifdef DBG
     int num_free_pages;
     int num_outputs;
@@ -187,6 +189,20 @@ typedef struct DevRes {
 #define SSE_MASK 15
 #define SSE_ALIGN 16
 
+ 
+typedef struct DrawArea {
+   HSURF bitmap;
+   SURFOBJ* surf_obj;
+   UINT8 *base_mem;
+} DrawArea;
+
+typedef struct PDev PDev;
+
+typedef struct SurfaceInfo {
+    DrawArea draw_area;
+    PDev *pdev;
+} SurfaceInfo;
+
 typedef struct PDev {
     HANDLE driver;
     HDEV eng;
@@ -197,8 +213,14 @@ typedef struct PDev {
     SIZEL resolution;
     UINT32 max_bitmap_size;
     ULONG bitmap_format;
+
     ULONG fb_size;
     BYTE* fb;
+    UINT64 fb_phys;
+    UINT8 dd_initialized;
+    UINT8 dd_slot_initialized;
+    UINT8 dd_mem_slot;
+
     ULONG stride;
     FLONG red_mask;
     FLONG green_mask;
@@ -229,12 +251,16 @@ typedef struct PDev {
 
     HSEMAPHORE malloc_sem;
     HSEMAPHORE print_sem;
+    HSEMAPHORE cmd_sem;
 
     PMemSlot *mem_slots;
     UINT8 num_mem_slot;
     UINT8 main_mem_slot;
     UINT8 slot_id_bits;
     UINT8 slot_gen_bits;
+    UINT8 *slots_generation;
+    UINT64 *ram_slot_start;
+    UINT64 *ram_slot_end;
     SPICE_ADDRESS va_slot_mask;
 
     UINT32 num_io_pages;
@@ -245,6 +271,7 @@ typedef struct PDev {
 
     UINT32 update_area_port;
     SpiceRect *update_area;
+    UINT32 *update_surface;
 
     UINT32 *mm_clock;
 
@@ -259,6 +286,9 @@ typedef struct PDev {
     UINT32 create_primary_port;
     UINT32 destroy_primary_port;
     UINT32 destroy_surface_wait_port;
+    UINT32 memslot_add_port;
+    UINT32 memslot_del_port;
+    UINT32 destroy_all_surfaces_port;
 
     UINT8* primary_memory_start;
     UINT32 primary_memory_size;
@@ -273,6 +303,11 @@ typedef struct PDev {
     UpdateTrace update_trace_items[NUM_UPDATE_TRACE_ITEMS];
 
     UINT8 FPUSave[16 * 4 + 15];
+
+    UINT32 n_surfaces;
+    SurfaceInfo *surfaces_info;
+
+    VIDEOMEMORY *pvmList;
 } PDev;
 
 
diff --git a/display/res.c b/display/res.c
index 041bf2e..318ea9c 100644
--- a/display/res.c
+++ b/display/res.c
@@ -15,6 +15,9 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <ddrawi.h>
+#include <ddraw.h>
+#include <dxmini.h>
 #include "os_dep.h"
 #include "res.h"
 #include "ioaccess.h"
@@ -22,6 +25,8 @@
 #include "mspace.h"
 #include "quic.h"
 #include "murmur_hash2a.h"
+#include "surface.h"
+#include "dd.h"
 
 #if (WINVER < 0x0501)
 #define WAIT_FOR_EVENT(pdev, event, timeout) (pdev)->WaitForEvent(event, timeout)
@@ -67,10 +72,12 @@ static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable);
 
 #define PUSH_CMD(pdev) do {                             \
     int notify;                                         \
+    EngAcquireSemaphore(pdev->cmd_sem);                 \
     SPICE_RING_PUSH(pdev->cmd_ring, notify);            \
     if (notify) {                                       \
         WRITE_PORT_UCHAR(pdev->notify_cmd_port, 0);     \
     }                                                   \
+    EngReleaseSemaphore(pdev->cmd_sem);                 \
 } while (0);
 
 #define PUSH_CURSOR_CMD(pdev) do {                      \
@@ -130,6 +137,15 @@ static _inline void DrawableAddRes(PDev *pdev, QXLDrawable *drawable, Resource *
     AddRes(pdev, output, res);
 }
 
+ 
+static _inline void SurfaceAddRes(PDev *pdev, QXLSurfaceCmd *surface, Resource *res)
+{
+    QXLOutput *output;
+
+    output = (QXLOutput *)((UINT8 *)surface - sizeof(QXLOutput));
+    AddRes(pdev, output, res);
+}
+
 static _inline void CursorCmdAddRes(PDev *pdev, QXLCursorCmd *cmd, Resource *res)
 {
     QXLOutput *output;
@@ -311,6 +327,10 @@ void CleanGlobalRes()
                 EngFreeMem(global_res[i].dynamic);
                 global_res[i].dynamic = NULL;
             }
+            if (global_res[i].surfaces_used) {
+                EngFreeMem(global_res[i].surfaces_used);
+                global_res[i].surfaces_used = NULL;
+            }
         }
         EngFreeMem(global_res);
         global_res = NULL;
@@ -347,6 +367,12 @@ static void InitRes(PDev *pdev)
         PANIC(pdev, "Res dynamic allocation failed\n");
     }
 
+    pdev->Res.surfaces_used = EngAllocMem(FL_ZERO_MEMORY, sizeof(UINT8) * pdev->n_surfaces,
+                                          ALLOC_TAG);
+    if (!pdev->Res.surfaces_used) {
+        PANIC(pdev, "Res surfaces_used allocation failed\n");
+    }
+
     pdev->Res.free_outputs = 0;
     InitMspace(&pdev->Res, pdev->io_pages_virt, pdev->num_io_pages * PAGE_SIZE);
     pdev->Res.update_id = *pdev->dev_update_id;
@@ -457,17 +483,21 @@ static QXLDrawable *GetDrawable(PDev *pdev)
     return(QXLDrawable *)output->data;
 }
 
-QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip)
+QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip, UINT32 surface_id)
 {
     QXLDrawable *drawable;
 
     ASSERT(pdev, pdev && area);
 
     drawable = GetDrawable(pdev);
+    drawable->surface_id = surface_id;
     drawable->type = type;
     drawable->effect = QXL_EFFECT_BLEND;
     drawable->self_bitmap = 0;
     drawable->mm_time = *pdev->mm_clock;
+    drawable->surfaces_dest[0] = -1;
+    drawable->surfaces_dest[1] = - 1;
+    drawable->surfaces_dest[2] = -1;
     CopyRect(&drawable->bbox, area);
 
     if (!SetClip(pdev, clip, drawable)) {
@@ -489,23 +519,141 @@ void PushDrawable(PDev *pdev, QXLDrawable *drawable)
     PUSH_CMD(pdev);
 }
 
-_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT8 **base_mem,
-                              QXLPHYSICAL *phys_mem, UINT8 allocation_type)
+static QXLSurfaceCmd *GetSurfaceCmd(PDev *pdev)
+{
+    QXLOutput *output;
+
+    output = (QXLOutput *)AllocMem(pdev, sizeof(QXLOutput) + sizeof(QXLSurfaceCmd));
+    output->num_res = 0;
+    ((QXLSurfaceCmd *)output->data)->release_info.id = (UINT64)output;
+    DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
+    ONDBG(pdev->Res.num_outputs++); //todo: atomic
+    return(QXLSurfaceCmd *)output->data;
+}
+
+QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id)
+{
+    QXLSurfaceCmd *surface_cmd;
+
+    ASSERT(pdev, pdev && area);
+
+    surface_cmd = GetSurfaceCmd(pdev);
+    surface_cmd->surface_id = surface_id;
+    surface_cmd->type = type;
+    surface_cmd->flags = 0;
+
+    return surface_cmd;
+}
+
+void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd)
+{
+    QXLCommand *cmd;
+
+    WaitForCmdRing(pdev);
+    cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
+    cmd->type = QXL_CMD_SURFACE;
+    cmd->data = PA(pdev, surface_cmd, pdev->main_mem_slot);
+    PUSH_CMD(pdev);
+}
+
+
+_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT32 *stride,
+                              UINT8 **base_mem, QXLPHYSICAL *phys_mem, UINT8 allocation_type)
 {
     DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
 
-    ASSERT(pdev, allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
-    ASSERT(pdev, x * y * depth /8 <= pdev->primary_memory_size);
+    switch (allocation_type) {
+    case DEVICE_BITMAP_ALLOCATION_TYPE_SURF0:
+        ASSERT(pdev, x * y * depth /8 <= pdev->primary_memory_size);
+        *base_mem = pdev->primary_memory_start;
+        *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+        *stride = x * depth / 8;
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
+        *base_mem = AllocMem(pdev, x * y * depth / 8);
+        *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+        *stride = x * depth / 8;
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM: { 
+        SURFACEALIGNMENT surfacealignment;
+
+        memset(&surfacealignment, 0, sizeof(surfacealignment));
+        surfacealignment.Linear.dwStartAlignment = 4;
+        surfacealignment.Linear.dwPitchAlignment = 4;
+        *base_mem = (UINT8 *)HeapVidMemAllocAligned((LPVIDMEM)pdev->pvmList, x * depth / 8, y,
+                                                    &surfacealignment, stride);
+        *phys_mem = PA(pdev, (PVOID)((UINT64)*base_mem), pdev->dd_mem_slot);
+        break;
+    }
+    default:
+        PANIC(pdev, "No allocation type");
+    }
+}
 
-    *base_mem = pdev->primary_memory_start;
-    *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
+                   UINT32 *stride, UINT8 **base_mem, UINT8 allocation_type)
+{
+    GetSurfaceMemory(pdev, x, y, depth, stride, base_mem, surface_phys, allocation_type);
 }
 
-BOOL QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
-                   UINT8 **base_mem, UINT8 allocation_type) {
-    ASSERT(pdev, allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
-    GetSurfaceMemory(pdev, x, y, depth, base_mem, surface_phys, allocation_type);
-    return TRUE;
+void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type)
+{
+    if (allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM) {
+        FreeMem(pdev, base_mem);
+    }
+}
+
+typedef struct InternalDelSurface {
+    UINT32 surface_id;
+    UINT8 allocation_type;
+} InternalDelSurface;
+
+
+static void FreeDelSurface(PDev *pdev, Resource *res)
+{
+    InternalDelSurface *internal;
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    internal = (InternalDelSurface *)res->res;
+    switch (internal->allocation_type) {
+    case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
+        FreeMem(pdev, pdev->surfaces_info[internal->surface_id].draw_area.base_mem);
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
+        VidMemFree(pdev->pvmList->lpHeap,
+                   (FLATPTR)pdev->surfaces_info[internal->surface_id].draw_area.base_mem);
+        break;
+    default:
+        PANIC(pdev, "bad allocation type");
+    }
+    FreeSurface(pdev, internal->surface_id);
+    FreeMem(pdev, res);
+
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+#define SURFACEDEL_ALLOC_BASE (sizeof(Resource) + sizeof(InternalDelSurface))
+
+void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UINT8 allocation_type)
+{
+    Resource *surface_res;
+    InternalDelSurface *internal;
+    size_t alloc_size;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    alloc_size = SURFACEDEL_ALLOC_BASE;
+    surface_res = AllocMem(pdev, alloc_size);
+    
+    surface_res->refs = 1;
+    surface_res->free = FreeDelSurface;
+
+    internal = (InternalDelSurface *)surface_res->res;
+    internal->surface_id = surface_id;
+    internal->allocation_type = allocation_type;
+
+    SurfaceAddRes(pdev, surface, surface_res);
+    RELEASE_RES(pdev, surface_res);
 }
 
 static void FreePath(PDev *pdev, Resource *res)
@@ -1512,6 +1660,15 @@ static _inline void SaveFPU(PDev *pdev)
     }
 }
 
+static void FreeSurfaceImage(PDev *pdev, Resource *res)
+{
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    FreeMem(pdev, res);
+
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
 #define BITMAP_ALLOC_BASE (sizeof(Resource) + sizeof(InternalImage) + sizeof(QXLDataChunk))
 
 static _inline Resource *GetBitmapImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans,
@@ -1789,7 +1946,8 @@ static _inline UINT32 get_image_serial()
 }
 
 BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
-                  SpiceRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache)
+                  SpiceRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache,
+                  INT32 *surface_dest)
 {
     Resource *image_res;
     InternalImage *internal;
@@ -1804,8 +1962,29 @@ BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SU
     ASSERT(pdev, !hash_key || use_cache);
     DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
     if (surf->iType != STYPE_BITMAP) {
-        DEBUG_PRINT((pdev, 0, "%s: copy from device doing nothing!!!\n", __FUNCTION__));
-        return FALSE;
+        UINT32 alloc_size;
+
+        DEBUG_PRINT((pdev, 9, "%s: copy from device\n", __FUNCTION__));
+
+        alloc_size = sizeof(Resource) + sizeof(InternalImage);
+        image_res = AllocMem(pdev, alloc_size);
+
+        ONDBG(pdev->num_bits_pages++);
+        image_res->refs = 1;
+        image_res->free = FreeSurfaceImage;
+
+        internal = (InternalImage *)image_res->res;
+
+        internal->image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
+        *surface_dest = internal->image.surface_image.surface_id = GetSurfaceId(surf);
+
+        *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+
+        DrawableAddRes(pdev, drawable, image_res);
+
+        RELEASE_RES(pdev, image_res);
+
+        return TRUE;
     }
 
     if (area->left < 0 || area->right > surf->sizlBitmap.cx ||
@@ -1910,7 +2089,7 @@ BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SU
 }
 
 BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys,
-                       SURFOBJ *surf, SpiceRect *area)
+                       SURFOBJ *surf, SpiceRect *area, INT32 *surface_dest)
 {
     Resource *image_res;
     InternalImage *internal;
@@ -1922,7 +2101,6 @@ BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phy
     INT32 height = area->bottom - area->top;
 
     DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-    ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP && surf->iType == STYPE_BITMAP);
     ASSERT(pdev, area->left >= 0 && area->right <= surf->sizlBitmap.cx &&
            area->top >= 0 && area->bottom <= surf->sizlBitmap.cy);
 
@@ -1932,6 +2110,32 @@ BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phy
                  surf->sizlBitmap.cx, surf->sizlBitmap.cy, surf->hsurf,
                  surf->iBitmapFormat));
 
+    if (surf->iType != STYPE_BITMAP) {
+        UINT32 alloc_size;
+
+        DEBUG_PRINT((pdev, 9, "%s: copy from device\n", __FUNCTION__));
+
+        alloc_size = sizeof(Resource) + sizeof(InternalImage);
+        image_res = AllocMem(pdev, alloc_size);
+
+        ONDBG(pdev->num_bits_pages++);
+        image_res->refs = 1;
+        image_res->free = FreeSurfaceImage;
+
+        internal = (InternalImage *)image_res->res;
+
+        internal->image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
+        *surface_dest = internal->image.surface_image.surface_id = GetSurfaceId(surf);
+
+        *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+        DrawableAddRes(pdev, drawable, image_res);
+        RELEASE_RES(pdev, image_res);
+
+        return TRUE;
+    }
+
+    ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP && surf->iType == STYPE_BITMAP);
+
     //todo: use GetChachImage
 
     // NOTE: Same BMF_DONTCACHE issue as in QXLGetBitmap
@@ -2024,7 +2228,7 @@ BOOL QXLGetBitsFromCache(PDev *pdev, QXLDrawable *drawable, UINT32 hash_key, QXL
 }
 
 BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, SpiceQMask *qxl_mask, SURFOBJ *mask, POINTL *pos,
-                BOOL invers, LONG width, LONG height)
+                BOOL invers, LONG width, LONG height, INT32 *surface_dest)
 {
     SpiceRect area;
 
@@ -2046,7 +2250,8 @@ BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, SpiceQMask *qxl_mask, SURFOBJ
     area.top = pos->y;
     area.bottom = area.top + height;
 
-    if (QXLGetBitmap(pdev, drawable, &qxl_mask->bitmap, mask, &area, NULL, NULL, TRUE)) {
+    if (QXLGetBitmap(pdev, drawable, &qxl_mask->bitmap, mask, &area, NULL, NULL, TRUE,
+                     surface_dest)) {
         qxl_mask->pos.x = area.left;
         qxl_mask->pos.y = area.top;
         return TRUE;
@@ -2082,7 +2287,7 @@ UINT8 *QXLGetBuf(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *buf_phys, UINT3
 }
 
 #ifdef UPDATE_CMD
-void UpdateArea(PDev *pdev, RECTL *area)
+void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
 {
     QXLCommand *cmd;
     QXLOutput *output;
@@ -2098,6 +2303,7 @@ void UpdateArea(PDev *pdev, RECTL *area)
 
     CopyRect(&updat_cmd->area, area);
     updat_cmd->update_id = ++pdev->Res.update_id;
+    updat_cmd->surface_id = surface_id;
 
     WaitForCmdRing(pdev);
     cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
@@ -2131,10 +2337,11 @@ void UpdateArea(PDev *pdev, RECTL *area)
 
 #else
 
-void UpdateArea(PDev *pdev, RECTL *area)
+void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
 {
     DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
     CopyRect(pdev->update_area, area);
+    *pdev->update_surface = surface_id;
     WRITE_PORT_UCHAR(pdev->update_area_port, 0);
 }
 
diff --git a/display/res.h b/display/res.h
index 5af8a26..90223ae 100644
--- a/display/res.h
+++ b/display/res.h
@@ -22,26 +22,32 @@
 
 UINT64 ReleaseOutput(PDev *pdev, UINT64 output_id);
 
-QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip);
+QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip, UINT32 surface_id);
 void PushDrawable(PDev *pdev, QXLDrawable *drawable);
+QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id);
+void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd);
 
-BOOL QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
-                    UINT8 **base_mem, UINT8 allocation_type);
+void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
+                   UINT32 *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);
 BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, SpiceQMask *qxl_mask, SURFOBJ *mask, POINTL *pos,
-                BOOL invers, LONG width, LONG height);
+                BOOL invers, LONG width, LONG height, INT32 *surface_dest);
 BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, SpiceBrush *qxl_brush,
-                            BRUSHOBJ *brush, POINTL *brush_pos);
+                            BRUSHOBJ *brush, POINTL *brush_pos, INT32 *surface_dest,
+                            SpiceRect *surface_rect);
 BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
-                  SpiceRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache);
+                  SpiceRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache,
+                  INT32 *surface_dest);
 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);
+                       SpiceRect *area, INT32 *surface_dest);
 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);
 
-void UpdateArea(PDev *pdev, RECTL *area);
+void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id);
 
 QXLCursorCmd *CursorCmd(PDev *pdev);
 void PushCursorCmd(PDev *pdev, QXLCursorCmd *cursor_cmd);
diff --git a/display/rop.c b/display/rop.c
index 83efdd3..82cd723 100644
--- a/display/rop.c
+++ b/display/rop.c
@@ -20,6 +20,7 @@
 #include "utils.h"
 #include "res.h"
 #include "rop.h"
+#include "surface.h"
 
 
 enum ROP3type {
@@ -382,21 +383,28 @@ ROP3Info rops3[] = {
 };
 
 
-static BOOL DoFill(PDev *pdev, RECTL *area, CLIPOBJ *clip, BRUSHOBJ *brush, POINTL *brush_pos,
-                   ROP3Info *rop_info, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask)
+static BOOL DoFill(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, BRUSHOBJ *brush,
+                   POINTL *brush_pos, ROP3Info *rop_info, SURFOBJ *mask, POINTL *mask_pos,
+                   BOOL invers_mask)
 {
     QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
 
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
     ASSERT(pdev, pdev && area && brush);
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_FILL, area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_FILL, area, clip, surface_id))) {
         return FALSE;
     }
 
-    if (!QXLGetBrush(pdev, drawable, &drawable->u.fill.brush, brush, brush_pos) ||
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (!QXLGetBrush(pdev, drawable, &drawable->u.fill.brush, brush, brush_pos,
+                     &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
         !QXLGetMask(pdev, drawable, &drawable->u.fill.mask, mask, mask_pos, invers_mask,
-                    area->right - area->left, area->bottom - area->top)) {
+                     width, height, &drawable->surfaces_dest[1])) {
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
     }
@@ -405,28 +413,37 @@ static BOOL DoFill(PDev *pdev, RECTL *area, CLIPOBJ *clip, BRUSHOBJ *brush, POIN
 
     drawable->effect = mask ? QXL_EFFECT_BLEND : rop_info->effect;
 
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
+    }
+
     PushDrawable(pdev, drawable);
     return TRUE;
 }
 
 static BOOL GetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *bitmap_phys, SURFOBJ *surf,
-                      SpiceRect *area, XLATEOBJ *color_trans, BOOL use_cache)
+                      SpiceRect *area, XLATEOBJ *color_trans, BOOL use_cache, INT32 *surface_dest)
 {
     DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
     if (surf->iType != STYPE_BITMAP) {
+        UINT32 surface_id;
+
         ASSERT(pdev, (PDev *)surf->dhpdev == pdev);
-        DEBUG_PRINT((pdev, 9, "%s copy from self\n", __FUNCTION__));
-        *bitmap_phys = 0;
-        drawable->self_bitmap = TRUE;
-        drawable->self_bitmap_area = *area;
-        area->right = area->right - area->left;
-        area->left = 0;
-        area->bottom = area->bottom - area->top;
-        area->top = 0;
-        return TRUE;
+        surface_id =  GetSurfaceId(surf);
+        if (surface_id == drawable->surface_id) {
+            DEBUG_PRINT((pdev, 9, "%s copy from self\n", __FUNCTION__));
+            *bitmap_phys = 0;
+            drawable->self_bitmap = TRUE;
+            drawable->self_bitmap_area = *area;
+            area->right = area->right - area->left;
+            area->left = 0;
+            area->bottom = area->bottom - area->top;
+            area->top = 0;
+            return TRUE;
+        }
     }
     return QXLGetBitmap(pdev, drawable, &drawable->u.opaque.src_bitmap, surf,
-                        area, color_trans, NULL, use_cache);
+                        area, color_trans, NULL, use_cache, surface_dest);
 }
 
 static _inline UINT8 GdiScaleModeToQxl(ULONG scale_mode)
@@ -435,31 +452,44 @@ static _inline UINT8 GdiScaleModeToQxl(ULONG scale_mode)
                                       SPICE_IMAGE_SCALE_MODE_NEAREST;
 }
 
-static BOOL DoOpaque(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
-                     XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
+static BOOL DoOpaque(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+                     RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
                      UINT16 rop_decriptor, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask,
                      ULONG scale_mode)
 {
     QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
 
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
     ASSERT(pdev, pdev && area && brush && src_rect && src);
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_OPAQUE, area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_OPAQUE, area, clip, surface_id))) {
         return FALSE;
     }
 
     drawable->u.opaque.scale_mode = GdiScaleModeToQxl(scale_mode);
     CopyRect(&drawable->u.opaque.src_area, src_rect);
-    if (!QXLGetBrush(pdev, drawable, &drawable->u.opaque.brush, brush, brush_pos) ||
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (!QXLGetBrush(pdev, drawable, &drawable->u.opaque.brush, brush, brush_pos,
+                     &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
         !QXLGetMask(pdev, drawable, &drawable->u.opaque.mask, mask, mask_pos, invers_mask,
-                    area->right - area->left, area->bottom - area->top) ||
+                    width, height, &drawable->surfaces_dest[1]) ||
         !GetBitmap(pdev, drawable, &drawable->u.opaque.src_bitmap, src,
-                   &drawable->u.opaque.src_area, color_trans, TRUE)) {
+                   &drawable->u.opaque.src_area, color_trans, TRUE,
+                   &drawable->surfaces_dest[2])) {
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
     }
 
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
+    }
+    CopyRect(&drawable->surfaces_rects[2], src_rect);
+
     drawable->u.opaque.rop_decriptor = rop_decriptor;
     drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
     PushDrawable(pdev, drawable);
@@ -521,7 +551,7 @@ 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)
+static BOOL TestSplitClips(PDev *pdev, SURFOBJ *src, RECTL *src_rect, CLIPOBJ *clip, SURFOBJ *mask)
 {
     UINT32 width;
     UINT32 height;
@@ -533,6 +563,10 @@ static BOOL TestSplitClips(PDev *pdev, RECTL *src_rect, CLIPOBJ *clip, SURFOBJ *
         return FALSE;
     }
 
+    if (src->iType != STYPE_BITMAP) {
+        return FALSE;
+    }
+
     width = src_rect->right - src_rect->left;
     height = src_rect->bottom - src_rect->top;
     src_space = width * height;
@@ -574,19 +608,24 @@ static BOOL TestSplitClips(PDev *pdev, RECTL *src_rect, CLIPOBJ *clip, SURFOBJ *
     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)
+static _inline BOOL DoPartialCopy(PDev *pdev, UINT32 surface_id, 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;
+    UINT32 width;
+    UINT32 height;
 
     SectRect(area_rect, clip_rect, &clip_area);
     if (IsEmptyRect(&clip_area)) {
         return TRUE;
     }
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, &clip_area, NULL))) {
+    width = clip_area.right - clip_area.left;
+    height = clip_area.bottom - clip_area.top;
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, &clip_area, NULL, surface_id))) {
         return FALSE;
     }
 
@@ -603,36 +642,41 @@ static _inline BOOL DoPartialCopy(PDev *pdev, SURFOBJ *src, RECTL *src_rect, REC
                                       clip_area.left;
 
     if(!GetBitmap(pdev, drawable, &drawable->u.copy.src_bitmap, src, &drawable->u.copy.src_area,
-                  color_trans, FALSE)) {
+                  color_trans, FALSE, &drawable->surfaces_dest[0])) {
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
     }
+    CopyRect(&drawable->surfaces_rects[0], src_rect);
     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)
+static BOOL DoCopy(PDev *pdev, UINT32 surface_id, 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)
 {
     QXLDrawable *drawable;
     BOOL use_cache;
+    UINT32 width;
+    UINT32 height;
 
     ASSERT(pdev, pdev && area && src_rect && src);
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
 
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
     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) &&
+    if (use_cache && TestSplitClips(pdev, src, 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)) {
+            if (!DoPartialCopy(pdev, surface_id, src, src_rect, area, &clip->rclBounds, color_trans,
+                               scale_mode, rop_decriptor)) {
                 return FALSE;
             }
         } else {
@@ -649,8 +693,8 @@ static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *
                 } 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)) {
+                    if (!DoPartialCopy(pdev, surface_id, src, src_rect, area, now, color_trans,
+                                       scale_mode, rop_decriptor)) {
                         return FALSE;
                     }
                 }
@@ -659,7 +703,7 @@ static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *
         return TRUE;
     }
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, area, clip, surface_id))) {
         return FALSE;
     }
 
@@ -672,22 +716,29 @@ static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *
     drawable->u.copy.scale_mode = GdiScaleModeToQxl(scale_mode);
     CopyRect(&drawable->u.copy.src_area, src_rect);
     if (!QXLGetMask(pdev, drawable, &drawable->u.copy.mask, mask, mask_pos, invers_mask,
-                    area->right - area->left, area->bottom - area->top) ||
+                    width, height, &drawable->surfaces_dest[0]) ||
         !GetBitmap(pdev, drawable, &drawable->u.copy.src_bitmap, src, &drawable->u.copy.src_area,
-                   color_trans, use_cache)) {
+                   color_trans, use_cache, &drawable->surfaces_dest[1])) {
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
     }
 
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+    }
+    CopyRect(&drawable->surfaces_rects[1], src_rect);
+
     drawable->u.copy.rop_decriptor = rop_decriptor;
     PushDrawable(pdev, drawable);
     DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
     return TRUE;
 }
 
-static BOOL DoCopyBits(PDev *pdev, CLIPOBJ *clip, RECTL *area, POINTL *src_pos)
+static BOOL DoCopyBits(PDev *pdev, UINT32 surface_id, CLIPOBJ *clip, RECTL *area, POINTL *src_pos)
 {
     QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height; 
 
     ASSERT(pdev, pdev && area && src_pos);
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
@@ -697,144 +748,199 @@ static BOOL DoCopyBits(PDev *pdev, CLIPOBJ *clip, RECTL *area, POINTL *src_pos)
         return TRUE;
     }
 
-    if (!(drawable = Drawable(pdev, QXL_COPY_BITS, area, clip))) {
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (!(drawable = Drawable(pdev, QXL_COPY_BITS, area, clip, surface_id))) {
         return FALSE;
     }
+
+    drawable->surfaces_dest[0] = surface_id;
+    CopyRectPoint(&drawable->surfaces_rects[0], src_pos, width, height);
+
     CopyPoint(&drawable->u.copy_bits.src_pos, src_pos);
     drawable->effect = QXL_EFFECT_OPAQUE;
     PushDrawable(pdev, drawable);
     return TRUE;
 }
 
-static BOOL DoBlend(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
-                    XLATEOBJ *color_trans, ROP3Info *rop_info, SURFOBJ *mask, POINTL *mask_pos,
-                    BOOL invers_mask, ULONG scale_mode)
+static BOOL DoBlend(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+                    RECTL *src_rect, XLATEOBJ *color_trans, ROP3Info *rop_info, SURFOBJ *mask,
+                    POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
 {
     QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height; 
 
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
     ASSERT(pdev, pdev && area && src_rect && src);
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_BLEND, area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_BLEND, area, clip, surface_id))) {
         return FALSE;
     }
 
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
     drawable->u.blend.scale_mode = GdiScaleModeToQxl(scale_mode);
     CopyRect(&drawable->u.blend.src_area, src_rect);
     if (!QXLGetMask(pdev, drawable, &drawable->u.blend.mask, mask, mask_pos, invers_mask,
-                    area->right - area->left, area->bottom - area->top) ||
+                    width, height, &drawable->surfaces_dest[0]) ||
         !GetBitmap(pdev, drawable, &drawable->u.blend.src_bitmap, src, &drawable->u.blend.src_area,
-                   color_trans, TRUE)) {
+                   color_trans, TRUE, &drawable->surfaces_dest[1])) {
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
     }
 
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+    }
+    CopyRect(&drawable->surfaces_rects[1], src_rect);
+
     drawable->u.blend.rop_decriptor = rop_info->method_data;
     drawable->effect = mask ? QXL_EFFECT_BLEND : rop_info->effect;
     PushDrawable(pdev, drawable);
     return TRUE;
 }
 
-static BOOL DoBlackness(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, POINTL *mask_pos,
-                        BOOL invers_mask)
+static BOOL DoBlackness(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask,
+                        POINTL *mask_pos, BOOL invers_mask)
 {
     QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
 
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
     ASSERT(pdev, pdev && area);
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_BLACKNESS, area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_BLACKNESS, area, clip, surface_id))) {
         return FALSE;
     }
 
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
     if (!QXLGetMask(pdev, drawable, &drawable->u.blackness.mask, mask, mask_pos, invers_mask,
-                    area->right - area->left, area->bottom - area->top)) {
+                    width, height, &drawable->surfaces_dest[0])) {
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
     }
 
+ if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+ }
+
     drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
     PushDrawable(pdev, drawable);
     return TRUE;
 }
 
-static BOOL DoWhiteness(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, POINTL *mask_pos,
-                        BOOL invers_mask)
+static BOOL DoWhiteness(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, 
+                        POINTL *mask_pos, BOOL invers_mask)
 {
     QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
 
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
     ASSERT(pdev, pdev && area);
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_WHITENESS, area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_WHITENESS, area, clip, surface_id))) {
         return FALSE;
     }
 
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
     if (!QXLGetMask(pdev, drawable, &drawable->u.whiteness.mask, mask, mask_pos, invers_mask,
-                    area->right - area->left, area->bottom - area->top)) {
+                    width, height, &drawable->surfaces_dest[0])) {
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
     }
 
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+    }
+
     drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
     PushDrawable(pdev, drawable);
     return TRUE;
 }
 
-static BOOL DoInvers(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, POINTL *mask_pos,
-                     BOOL invers_mask)
+static BOOL DoInvers(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, 
+                     POINTL *mask_pos, BOOL invers_mask)
 {
     QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
 
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
     ASSERT(pdev, pdev && area);
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_INVERS, area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_INVERS, area, clip, surface_id))) {
         return FALSE;
     }
 
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
     if (!QXLGetMask(pdev, drawable, &drawable->u.invers.mask, mask, mask_pos, invers_mask,
-                    area->right - area->left, area->bottom - area->top)) {
+                    width, height, &drawable->surfaces_dest[0])) {
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
     }
 
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+    }
+
     drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_REVERT_ON_DUP;
     PushDrawable(pdev, drawable);
     return TRUE;
 }
 
-static BOOL DoROP3(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
-                   XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos, UINT8 rop3,
-                   SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
+static BOOL DoROP3(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+                   RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
+                   UINT8 rop3, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
 {
     QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
 
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
     ASSERT(pdev, pdev && area && brush && src_rect && src);
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_ROP3, area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_ROP3, area, clip, surface_id))) {
         return FALSE;
     }
 
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
     drawable->u.rop3.scale_mode = GdiScaleModeToQxl(scale_mode);
     CopyRect(&drawable->u.rop3.src_area, src_rect);
-    if (!QXLGetBrush(pdev, drawable, &drawable->u.rop3.brush, brush, brush_pos) ||
+    if (!QXLGetBrush(pdev, drawable, &drawable->u.rop3.brush, brush, brush_pos,
+                     &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
         !QXLGetMask(pdev, drawable, &drawable->u.rop3.mask, mask, mask_pos, invers_mask,
-                    area->right - area->left, area->bottom - area->top) ||
+                    width, height, &drawable->surfaces_dest[1]) ||
         !GetBitmap(pdev, drawable, &drawable->u.rop3.src_bitmap, src, &drawable->u.rop3.src_area,
-                   color_trans, TRUE)) {
+                   color_trans, TRUE, &drawable->surfaces_dest[2])) {
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
     }
 
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
+    }
+    CopyRect(&drawable->surfaces_rects[2], src_rect);
+
     drawable->u.rop3.rop3 = rop3;
     drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_BLEND; //for now
     PushDrawable(pdev, drawable);
     return TRUE;
 }
 
-static SURFOBJ *Copy16bppArea(PDev *pdev, RECTL *area)
+static SURFOBJ *Copy16bppArea(PDev *pdev, SURFOBJ *src, RECTL *area)
 {
     SIZEL  size;
     HSURF bitmap;
@@ -843,6 +949,9 @@ static SURFOBJ *Copy16bppArea(PDev *pdev, RECTL *area)
     UINT8 *dest_end_line;
     LONG src_stride;
     UINT8 *src_line;
+    SurfaceInfo *surface;
+
+    surface = (SurfaceInfo *)src->dhsurf;
 
     size.cx = area->right - area->left;
     size.cy = area->bottom - area->top;
@@ -864,8 +973,9 @@ static SURFOBJ *Copy16bppArea(PDev *pdev, RECTL *area)
 
     dest_line = surf_obj->pvScan0;
     dest_end_line = dest_line + surf_obj->lDelta * surf_obj->sizlBitmap.cy;
-    src_stride = pdev->draw_surf->lDelta;
-    src_line = (UINT8 *)pdev->draw_surf->pvScan0 + area->top * src_stride + (area->left << 2);
+    src_stride = surface->draw_area.surf_obj->lDelta;
+    src_line = (UINT8 *)surface->draw_area.surf_obj->pvScan0 + area->top * src_stride +
+                        (area->left << 2);
 
     for (; dest_line != dest_end_line; dest_line += surf_obj->lDelta, src_line += src_stride) {
         UINT16 *dest = (UINT16 *)dest_line;
@@ -885,13 +995,16 @@ error:
 
 }
 
-static BOOL BitBltFromDev(PDev *pdev, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *clip,
+static BOOL BitBltFromDev(PDev *pdev, SURFOBJ *src, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *clip,
                    XLATEOBJ *color_trans, RECTL *dest_rect, POINTL src_pos,
                    POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4)
 {
     RECTL area;
     SURFOBJ* surf_obj;
     BOOL ret;
+    UINT32 surface_id;
+
+    surface_id = GetSurfaceId(src);
 
     DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
 
@@ -900,17 +1013,20 @@ static BOOL BitBltFromDev(PDev *pdev, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *cli
     area.left = MAX(0, src_pos.x);
     area.right = MIN(src_pos.x + dest_rect->right - dest_rect->left, pdev->resolution.cx);
 
-    UpdateArea(pdev, &area);
+    UpdateArea(pdev, &area, surface_id);
 
     if (pdev->bitmap_format == BMF_16BPP) {
-        surf_obj = Copy16bppArea(pdev, &area);
+        surf_obj = Copy16bppArea(pdev, src, &area);
         if (!surf_obj) {
             return FALSE;
         }
         src_pos.y = src_pos.y - area.top;
         src_pos.x = src_pos.x - area.left;
     } else {
-        surf_obj = pdev->draw_surf;
+        SurfaceInfo *surface;
+
+        surface = (SurfaceInfo *)src->dhsurf;
+        surf_obj = surface->draw_area.surf_obj;
     }
 
     if (rop4 == 0xcccc) {
@@ -930,9 +1046,10 @@ static BOOL BitBltFromDev(PDev *pdev, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *cli
     return ret;
 }
 
-BOOL _inline __DrvBitBlt(PDev *pdev, RECTL *dest_rect, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
-                         XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos, ULONG rop3,
-                         SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
+BOOL _inline __DrvBitBlt(PDev *pdev, UINT32 surface_id, RECTL *dest_rect, CLIPOBJ *clip,
+                        SURFOBJ  *src, RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, 
+                        POINTL *brush_pos, ULONG rop3, SURFOBJ *mask, POINTL *mask_pos,
+                        BOOL invers_mask, ULONG scale_mode)
 {
     ROP3Info *rop_info = &rops3[rop3];
 
@@ -940,26 +1057,27 @@ BOOL _inline __DrvBitBlt(PDev *pdev, RECTL *dest_rect, CLIPOBJ *clip, SURFOBJ *s
 
     switch (rop_info->method_type) {
     case ROP3_TYPE_FILL:
-        return DoFill(pdev, dest_rect, clip, brush, brush_pos, rop_info, mask, mask_pos,
+        return DoFill(pdev, surface_id, dest_rect, clip, brush, brush_pos, rop_info, mask, mask_pos,
                       invers_mask);
     case ROP3_TYPE_OPAQUE:
-        return DoOpaque(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos,
-                            rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
+        return DoOpaque(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                        brush_pos, rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
     case ROP3_TYPE_COPY:
-        return DoCopy(pdev, dest_rect, clip, src, src_rect, color_trans, rop_info->method_data,
-                      mask, mask_pos, invers_mask, scale_mode);
+        return DoCopy(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans,
+                      rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
     case ROP3_TYPE_BLEND:
-        return DoBlend(pdev, dest_rect, clip, src, src_rect, color_trans, rop_info, mask, mask_pos,
-                       invers_mask, scale_mode);
+        return DoBlend(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, rop_info,
+                       mask, mask_pos, invers_mask, scale_mode);
     case ROP3_TYPE_BLACKNESS:
-        return DoBlackness(pdev, dest_rect, clip, mask, mask_pos, invers_mask);
+        return DoBlackness(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
     case ROP3_TYPE_WHITENESS:
-        return DoWhiteness(pdev, dest_rect, clip, mask, mask_pos, invers_mask);
+        return DoWhiteness(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
     case ROP3_TYPE_INVERS:
-        return DoInvers(pdev, dest_rect, clip, mask, mask_pos, invers_mask);
+        return DoInvers(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
     case ROP3_TYPE_ROP3:
-        return DoROP3(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos,
-                      (UINT8)rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
+        return DoROP3(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                      brush_pos, (UINT8)rop_info->method_data, mask, mask_pos, invers_mask,
+                      scale_mode);
     case ROP3_TYPE_NOP:
         return TRUE;
     default:
@@ -1055,14 +1173,20 @@ static QXLRESULT BitBltCommon(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *
     SURFOBJ *brush_mask = NULL;
 #endif
     QXLRESULT res;
+    UINT32 surface_id;
+
+    ASSERT(pdev, dest->iType != STYPE_BITMAP);
+
+    surface_id = GetSurfaceId(dest);
 
     if (!PrepareBrush(brush)) {
         return QXL_FAILED;
     }
 
     if ((rop3 = rop4 & 0xff) == (second_rop3 = ((rop4 >> 8) & 0xff))) {
-        return __DrvBitBlt(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos,
-                           rop3, NULL, NULL, FALSE, scale_mode) ? QXL_SUCCESS : QXL_FAILED;
+        return __DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                           brush_pos, rop3, NULL, NULL, FALSE, scale_mode) ? QXL_SUCCESS :
+                           QXL_FAILED;
     }
 
     if (!mask) {
@@ -1080,15 +1204,17 @@ static QXLRESULT BitBltCommon(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *
     }
     DEBUG_PRINT((pdev, 5, "%s: mask, rop4 is 0x%x\n", __FUNCTION__, rop4));
     ASSERT(pdev, mask_pos);
-    res = (__DrvBitBlt(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos, rop3,
-                      mask, mask_pos, FALSE, scale_mode) &&
-          __DrvBitBlt(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos,
-                      second_rop3, mask, mask_pos, TRUE, scale_mode)) ? QXL_SUCCESS : QXL_FAILED;
+    res = (__DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                       brush_pos, rop3, mask, mask_pos, FALSE, scale_mode) &&
+          __DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                      brush_pos, second_rop3, mask, mask_pos, TRUE, scale_mode)) ? QXL_SUCCESS :
+                      QXL_FAILED;
 #ifdef SUPPORT_BRUSH_AS_MASK
     if (brush_mask) {
         //free brush_mask;
     }
 #endif
+
     return res;
 }
 
@@ -1151,8 +1277,6 @@ static QXLRESULT _BitBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask,
     }
 #endif
 
-    ASSERT(pdev, dest->iType == STYPE_BITMAP || dest->hsurf == pdev->surf);
-    ASSERT(pdev, !src || src->iType == STYPE_BITMAP || src->hsurf == pdev->surf);
     ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
            dest_rect->top < dest_rect->bottom);
 
@@ -1169,12 +1293,14 @@ static QXLRESULT _BitBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask,
         local_pos.y = src_pos->y + (area.top - dest_rect->top);
 
         if (dest->iType == STYPE_BITMAP) {
-            return BitBltFromDev(pdev, dest, mask, clip, color_trans, &area, local_pos, mask_pos,
-                                 brush, brush_pos, rop4) ? QXL_SUCCESS : QXL_FAILED;
+            return BitBltFromDev(pdev, src, dest, mask, clip, color_trans, &area, local_pos,
+                                 mask_pos, brush, brush_pos, rop4) ? QXL_SUCCESS : QXL_FAILED;
         }
 
-        if (src->iType != STYPE_BITMAP && rop4 == 0xcccc) { //SRCCOPY no mask
-            return DoCopyBits(pdev, clip, &area, &local_pos) ? QXL_SUCCESS : QXL_FAILED;
+        if (src->iType != STYPE_BITMAP
+            && GetSurfaceId(src) == GetSurfaceId(dest) && rop4 == 0xcccc) { //SRCCOPY no mask
+            return DoCopyBits(pdev, GetSurfaceId(src), clip, &area, &local_pos) ?
+                              QXL_SUCCESS : QXL_FAILED;
         }
 
         src_rect.left = local_pos.x;
@@ -1185,6 +1311,7 @@ static QXLRESULT _BitBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask,
     } else {
         src_rect_ptr = NULL;
     }
+
     return BitBltCommon(pdev, dest, src, mask, clip, color_trans, &area, src_rect_ptr,
                         mask_pos, brush, brush_pos, rop4, COLORONCOLOR, NULL);
 }
@@ -1197,14 +1324,13 @@ BOOL APIENTRY DrvBitBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *cli
     QXLRESULT res;
 
     if (dest->iType == STYPE_BITMAP) {
-        ASSERT(NULL, src && src->iType != STYPE_BITMAP && src->dhpdev && src_pos);
         pdev = (PDev *)src->dhpdev;
     } else {
-        ASSERT(NULL, dest->dhpdev);
         pdev = (PDev *)dest->dhpdev;
-        CountCall(pdev, CALL_COUNTER_BIT_BLT);
     }
 
+    CountCall(pdev, CALL_COUNTER_BIT_BLT);
+
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
     if ((res = _BitBlt(pdev, dest, src, mask, clip, color_trans, dest_rect, src_pos, mask_pos,
                        brush, brush_pos, rop4))) {
@@ -1216,6 +1342,7 @@ BOOL APIENTRY DrvBitBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *cli
         return FALSE;
 
     }
+
     DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
     return TRUE;
 }
@@ -1226,14 +1353,13 @@ BOOL APIENTRY DrvCopyBits(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip,
     PDev *pdev;
 
     if (dest->iType == STYPE_BITMAP) {
-        ASSERT(NULL, src && src->iType != STYPE_BITMAP && src->dhpdev && src_pos);
         pdev = (PDev *)src->dhpdev;
     } else {
-        ASSERT(NULL, dest->dhpdev);
         pdev = (PDev *)dest->dhpdev;
-        CountCall(pdev, CALL_COUNTER_BIT_BLT);
     }
 
+    CountCall(pdev, CALL_COUNTER_BIT_BLT);
+
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
 
     return _BitBlt(pdev, dest, src, NULL, clip, color_trans, dest_rect, src_pos, NULL, NULL,
@@ -1389,13 +1515,12 @@ BOOL APIENTRY DrvStretchBltROP(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPO
     PDev *pdev;
     QXLRESULT res;
 
-    if (!src || src->iType != STYPE_BITMAP) {
-        ASSERT(NULL, src->dhpdev);
+    if (src && src->iType != STYPE_BITMAP) {
         pdev = (PDev *)src->dhpdev;
-        goto punt;
+    } else {
+        pdev = (PDev *)dest->dhpdev;
     }
 
-    ASSERT(NULL, dest && dest->iType != STYPE_BITMAP && dest->dhpdev);
     pdev = (PDev *)dest->dhpdev;
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
     CountCall(pdev, CALL_COUNTER_STRETCH_BLT_ROP);
@@ -1425,11 +1550,10 @@ BOOL APIENTRY DrvStretchBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ
 
     ASSERT(NULL, src);
     if (src->iType != STYPE_BITMAP) {
-        ASSERT(NULL, src->dhpdev);
         pdev = (PDev *)src->dhpdev;
-        goto punt;
+    } else {
+        pdev = (PDev *)dest->dhpdev;
     }
-    ASSERT(NULL, dest && dest->iType != STYPE_BITMAP && dest->dhpdev);
     pdev = (PDev *)dest->dhpdev;
 
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
@@ -1522,11 +1646,11 @@ BOOL APIENTRY DrvAlphaBlend(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ
 
     ASSERT(NULL, src && dest);
     if (src->iType != STYPE_BITMAP) {
-        ASSERT(NULL, src->dhpdev);
         pdev = (PDev *)src->dhpdev;
-        goto punt;
+    } else {
+        pdev = (PDev *)dest->dhpdev;
     }
-    ASSERT(NULL, dest->iType != STYPE_BITMAP && dest->dhpdev);
+
     pdev = (PDev *)dest->dhpdev;
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
 
@@ -1562,7 +1686,7 @@ BOOL APIENTRY DrvAlphaBlend(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ
         return TRUE;
     }
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_ALPHA_BLEND, &area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_ALPHA_BLEND, &area, clip, GetSurfaceId(dest)))) {
         DEBUG_PRINT((pdev, 0, "%s: Drawable failed\n", __FUNCTION__));
         return FALSE;
     }
@@ -1571,18 +1695,21 @@ BOOL APIENTRY DrvAlphaBlend(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ
         src_rect = &local_src;
     }
 
+    CopyRect(&drawable->surfaces_rects[0], src_rect);
     CopyRect(&drawable->u.alpha_blend.src_area, src_rect);
     if (bland->BlendFunction.AlphaFormat == AC_SRC_ALPHA) {
         ASSERT(pdev, src->iBitmapFormat == BMF_32BPP);
         if (!QXLGetAlphaBitmap(pdev, drawable, &drawable->u.alpha_blend.src_bitmap, src,
-                               &drawable->u.alpha_blend.src_area)) {
+                               &drawable->u.alpha_blend.src_area,
+                               &drawable->surfaces_dest[0])) {
             DEBUG_PRINT((pdev, 0, "%s: QXLGetAlphaBitmap failed\n", __FUNCTION__));
             ReleaseOutput(pdev, drawable->release_info.id);
             return FALSE;
         }
     } else {
         if (!QXLGetBitmap(pdev, drawable, &drawable->u.alpha_blend.src_bitmap, src,
-                        &drawable->u.alpha_blend.src_area, color_trans, NULL, TRUE)) {
+                        &drawable->u.alpha_blend.src_area, color_trans, NULL, TRUE,
+                        &drawable->surfaces_dest[0])) {
             DEBUG_PRINT((pdev, 0, "%s: QXLGetBitmap failed\n", __FUNCTION__));
             ReleaseOutput(pdev, drawable->release_info.id);
             return FALSE;
@@ -1613,11 +1740,11 @@ BOOL APIENTRY DrvTransparentBlt(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLAT
     if (src->iType != STYPE_BITMAP) {
         ASSERT(NULL, src->dhpdev);
         pdev = (PDev *)src->dhpdev;
-        goto punt;
+    } else {
+        ASSERT(NULL, dest->dhpdev);
+        pdev = (PDev *)dest->dhpdev;
     }
 
-    ASSERT(NULL, dest->iType != STYPE_BITMAP && dest->dhpdev);
-    pdev = (PDev *)dest->dhpdev;
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
 
     ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
@@ -1643,7 +1770,7 @@ BOOL APIENTRY DrvTransparentBlt(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLAT
         return TRUE;
     }
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_TRANSPARENT, &area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_TRANSPARENT, &area, clip, GetSurfaceId(dest)))) {
         DEBUG_PRINT((pdev, 0, "%s: Drawable failed\n", __FUNCTION__));
         return FALSE;
     }
@@ -1653,8 +1780,10 @@ BOOL APIENTRY DrvTransparentBlt(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLAT
     }
 
     CopyRect(&drawable->u.transparent.src_area, src_rect);
+    CopyRect(&drawable->surfaces_rects[0], src_rect);
     if (!QXLGetBitmap(pdev, drawable, &drawable->u.transparent.src_bitmap, src,
-                      &drawable->u.transparent.src_area, color_trans, NULL, TRUE)) {
+                      &drawable->u.transparent.src_area, color_trans, NULL, TRUE,
+                      &drawable->surfaces_dest[0])) {
         DEBUG_PRINT((pdev, 0, "%s: QXLGetBitmap failed\n", __FUNCTION__));
         ReleaseOutput(pdev, drawable->release_info.id);
         return FALSE;
diff --git a/display/sources b/display/sources
index 6c1d5c7..617f42c 100644
--- a/display/sources
+++ b/display/sources
@@ -30,5 +30,6 @@ SOURCES=driver.c        \
         mspace.c        \
         quic.c          \
         surface.c       \
+        dd.c            \
         driver.rc
 
diff --git a/display/surface.c b/display/surface.c
index 36ae44c..f15255a 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -36,14 +36,18 @@
 #include "res.h"
 #include "surface.h"
 
-BOOL CreateDrawArea(PDev *pdev, DrawArea *drawarea, UINT8 *base_mem, UINT32 cx, UINT32 cy)
+BOOL CreateDrawArea(PDev *pdev, UINT8 *base_mem, UINT32 cx, UINT32 cy, UINT32 stride,
+                    UINT32 surface_id)
 {
     SIZEL  size;
+    DrawArea *drawarea;
 
     size.cx = cx;
     size.cy = cy;
 
-    if (!(drawarea->bitmap = (HSURF)EngCreateBitmap(size, size.cx << 2, BMF_32BPP, 0, base_mem))) {
+    drawarea = &pdev->surfaces_info[surface_id].draw_area;
+
+    if (!(drawarea->bitmap = (HSURF)EngCreateBitmap(size, stride, BMF_32BPP, 0, base_mem))) {
         DEBUG_PRINT((pdev, 0, "%s: EngCreateBitmap failed\n", __FUNCTION__));
         return FALSE;
     }
@@ -58,6 +62,8 @@ BOOL CreateDrawArea(PDev *pdev, DrawArea *drawarea, UINT8 *base_mem, UINT32 cx,
         goto error;
     }
 
+    drawarea->base_mem = base_mem;
+
     return TRUE;
 error:
     EngDeleteSurface(drawarea->bitmap);
@@ -66,15 +72,19 @@ error:
 
 VOID FreeDrawArea(DrawArea *drawarea)
 {
-    EngUnlockSurface(drawarea->surf_obj);
-    EngDeleteSurface(drawarea->bitmap);
+    if (drawarea->surf_obj) {
+        EngUnlockSurface(drawarea->surf_obj);
+        EngDeleteSurface(drawarea->bitmap);
+        drawarea->surf_obj = NULL;
+    }
 }
 
 HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
-                           UINT8 **base_mem, UINT8 allocation_type)
+                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type)
 {
     UINT8 depth;
     HBITMAP surf;
+    UINT32 stride;
 
     switch (format) {
         case BMF_8BPP:
@@ -93,7 +103,7 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
             return 0;
     };
 
-    if (!(surf = EngCreateDeviceBitmap((DHSURF)pdev, size, format))) {
+    if (!(surf = EngCreateDeviceBitmap((DHSURF)&pdev->surfaces_info[surface_id], size, format))) {
         DEBUG_PRINT((NULL, 0, "%s: create device surface failed, 0x%lx\n",
                      __FUNCTION__, pdev));
         goto out_error1;
@@ -104,26 +114,61 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
                              HOOK_STRETCHBLTROP | HOOK_TRANSPARENTBLT | HOOK_ALPHABLEND
 #ifdef CALL_TEST
                              | HOOK_PLGBLT | HOOK_FILLPATH | HOOK_STROKEANDFILLPATH | HOOK_LINETO |
-                             HOOK_GRADIENTFILL
+                             HOOK_GRADIENTFILL 
 #endif
                              )) {
         DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
         goto out_error2;
     }
 
-    if (!QXLGetSurface(pdev, phys_mem, size.cx, size.cy, 32, base_mem, allocation_type)) {
+    pdev->surfaces_info[surface_id].pdev = pdev;
+
+    QXLGetSurface(pdev, phys_mem, size.cx, size.cy, depth, &stride, base_mem, allocation_type);
+    if (!*base_mem) {
         goto out_error2;
     }
 
+    if (!CreateDrawArea(pdev, *base_mem, 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.depth = depth;
+        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);
+    }
+
     return surf;
 
+out_error3:
+    QXLDelSurface(pdev, *base_mem, allocation_type);
 out_error2:
+    FreeSurface(pdev, surface_id);
     EngDeleteSurface((HSURF)surf);
 out_error1:
     return 0;
 }
 
-VOID DeleteDeviceBitmap(HSURF surf)
+VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
 {
-    EngDeleteSurface(surf);
+    DrawArea *drawarea;
+
+    drawarea = &pdev->surfaces_info[surface_id].draw_area;
+
+    FreeDrawArea(drawarea);
+
+    if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0 &&
+        pdev->Res.surfaces_used[surface_id]) {
+        QXLSurfaceCmd *surface;
+
+        surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_DESTROY, surface_id);
+        QXLGetDelSurface(pdev, surface, surface_id, allocation_type);
+        PushSurfaceCmd(pdev, surface);
+    }
 }
diff --git a/display/surface.h b/display/surface.h
index a384020..e0ecc57 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -1,20 +1,54 @@
 #ifndef SURFACE_H
 #define SURFACE_H
 
+#include "qxldd.h"
+
+static _inline UINT32 GetSurfaceId(SURFOBJ *surf)
+{
+    PDev *pdev;
+    SurfaceInfo *surface;
+    UINT32 surface_id;
+
+    pdev = (PDev *)surf->dhpdev;
+
+    surface = (SurfaceInfo *)surf->dhsurf;
+    surface_id = surface - pdev->surfaces_info;
+    return surface_id;
+}
+
+static _inline void FreeSurface(PDev *pdev, UINT32 surface_id)
+{
+   pdev->Res.surfaces_used[surface_id] = 0;
+}
+
+
+static UINT32 GetFreeSurface(PDev *pdev)
+{
+    UINT32 x;
+
+    //not effective, fix me
+    for (x = 1; x < pdev->n_surfaces; ++x) {
+        if (!pdev->Res.surfaces_used[x]) {
+            pdev->Res.surfaces_used[x] = 1;
+            return x;
+        }
+    }
+
+    return 0;
+}
+
 enum {
     DEVICE_BITMAP_ALLOCATION_TYPE_SURF0,
+    DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM,
+    DEVICE_BITMAP_ALLOCATION_TYPE_VRAM,
 };
 
-typedef struct DrawArea {
-   HSURF bitmap;
-   SURFOBJ* surf_obj;
-} DrawArea;
-
-BOOL CreateDrawArea(PDev *pdev, DrawArea *drawarea, UINT8 *base_mem, UINT32 cx, UINT32 cy);
+BOOL CreateDrawArea(PDev *pdev, UINT8 *base_mem, UINT32 cx, UINT32 cy, UINT32 stride,
+                    UINT32 surface_id);
 VOID FreeDrawArea(DrawArea *drawarea);
 
 HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
-                           UINT8 **base_mem, UINT8 allocation_type);
-VOID DeleteDeviceBitmap(HSURF surf);
+                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type);
+VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type);
 
 #endif
diff --git a/display/text.c b/display/text.c
index c661544..9d04472 100644
--- a/display/text.c
+++ b/display/text.c
@@ -20,6 +20,7 @@
 #include "utils.h"
 #include "res.h"
 #include "rop.h"
+#include "surface.h"
 
 BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *clip,
                          RECTL *ignored, RECTL *opaque_rect,
@@ -31,12 +32,15 @@ BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *cli
     ROP3Info *back_rop;
     PDev* pdev;
     RECTL area;
+    UINT32 surface_id;
 
     if (!(pdev = (PDev *)surf->dhpdev)) {
         DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
         return FALSE;
     }
 
+    surface_id = GetSurfaceId(surf);
+
     CountCall(pdev, CALL_COUNTER_TEXT_OUT);
 
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
@@ -62,13 +66,14 @@ BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *cli
         }
     }
 
-    if (!(drawable = Drawable(pdev, QXL_DRAW_TEXT, &area, clip))) {
+    if (!(drawable = Drawable(pdev, QXL_DRAW_TEXT, &area, clip, surface_id))) {
         return FALSE;
     }
 
     if (opaque_rect) {
         ASSERT(pdev, back_brash && brushs_origin);
-        if (!QXLGetBrush(pdev, drawable, &drawable->u.text.back_brush, back_brash, brushs_origin)) {
+        if (!QXLGetBrush(pdev, drawable, &drawable->u.text.back_brush, back_brash, brushs_origin,
+                         &drawable->surfaces_dest[0], &drawable->surfaces_rects[0])) {
             goto error;
         }
         CopyRect(&drawable->u.text.back_area, &area);
@@ -87,7 +92,8 @@ BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *cli
     if (!((fore_rop->flags | back_rop->flags) & ROP3_BRUSH)) {
         drawable->u.stroke.brush.type = SPICE_BRUSH_TYPE_NONE;
     } else if (!QXLGetBrush(pdev, drawable, &drawable->u.text.fore_brush, fore_brush,
-                            brushs_origin)) {
+                            brushs_origin, &drawable->surfaces_dest[1],
+                            &drawable->surfaces_rects[1])) {
         DEBUG_PRINT((pdev, 0, "%s: get brush failed\n", __FUNCTION__));
         goto error;
     }
diff --git a/display/utils.h b/display/utils.h
index 74f3476..124aff7 100644
--- a/display/utils.h
+++ b/display/utils.h
@@ -46,6 +46,12 @@ static _inline LONG RectSize(RECTL *rect)
     return (rect->right - rect->left) * (rect->bottom - rect->top);
 }
 
+#define CopyRectPoint(dest, src, width, height) \
+    (dest)->left = (src)->x; \
+    (dest)->right = (src)->x + width; \
+    (dest)->top = (src)->y; \
+    (dest)->bottom = (src)->y + height; 
+
 #define SameRect(r1, r2) ((r1)->left == (r2)->left && (r1)->right == (r2)->right && \
                           (r1)->top == (r2)->top && (r1)->bottom == (r2)->bottom)
 
diff --git a/include/qxl_driver.h b/include/qxl_driver.h
index 12f5aac..566648c 100644
--- a/include/qxl_driver.h
+++ b/include/qxl_driver.h
@@ -66,6 +66,7 @@ typedef struct QXLDriverInfo {
 
     UINT32 update_area_port;
     SpiceRect *update_area;
+    UINT32 *update_surface;
 
     UINT32 *mm_clock;
 
@@ -79,15 +80,25 @@ typedef struct QXLDriverInfo {
     UINT8 main_mem_slot_id;
     UINT8 slot_id_bits;
     UINT8 slot_gen_bits;
+    UINT8 *slots_generation;
+    UINT64 *ram_slot_start;
+    UINT64 *ram_slot_end;
     MemSlot main_mem_slot;
 
     UINT32 destroy_surface_wait_port;
     UINT32 create_primary_port;
     UINT32 destroy_primary_port;
+    UINT32 memslot_add_port;
+    UINT32 memslot_del_port;
+    UINT32 destroy_all_surfaces_port;
 
     UINT32 dev_id;
 
     QXLSurfaceCreate *primary_surface_create;
+
+    UINT32 n_surfaces;
+
+    UINT64 fb_phys;
 } QXLDriverInfo;
 
 
diff --git a/miniport/qxl.c b/miniport/qxl.c
index fe5449c..9c7e1bc 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -946,6 +946,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             driver_info->notify_cmd_port = dev_ext->io_port + QXL_IO_NOTIFY_CMD;
             driver_info->notify_cursor_port = dev_ext->io_port + QXL_IO_NOTIFY_CURSOR;
             driver_info->notify_oom_port = dev_ext->io_port + QXL_IO_NOTIFY_OOM;
+
             driver_info->log_port = dev_ext->io_port + QXL_IO_LOG;
             driver_info->log_buf = dev_ext->ram_header->log_buf;
 
@@ -957,6 +958,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             driver_info->log_level = &dev_ext->rom->log_level;
             driver_info->update_area_port = dev_ext->io_port + QXL_IO_UPDATE_AREA;
             driver_info->update_area = &dev_ext->ram_header->update_area;
+            driver_info->update_surface = &dev_ext->ram_header->update_surface;
 
             driver_info->num_pages = dev_ext->rom->num_pages;
             driver_info->io_pages_virt = dev_ext->ram_start + driver_info->surface0_area_size;
@@ -967,17 +969,27 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             driver_info->num_mem_slot = dev_ext->rom->slots_end;
             driver_info->slot_gen_bits = dev_ext->rom->slot_gen_bits;
             driver_info->slot_id_bits = dev_ext->rom->slot_id_bits;
+	    driver_info->slots_generation = &dev_ext->rom->slot_generation;
+	    driver_info->ram_slot_start = &dev_ext->ram_header->mem_slot.mem_start;
+	    driver_info->ram_slot_end = &dev_ext->ram_header->mem_slot.mem_end;
             driver_info->main_mem_slot = dev_ext->mem_slots[driver_info->main_mem_slot_id];
 
 #if (WINVER < 0x0501)
             driver_info->WaitForEvent = QXLWaitForEvent;
 #endif
             driver_info->destroy_surface_wait_port = dev_ext->io_port + QXL_IO_DESTROY_SURFACE_WAIT;
+            driver_info->destroy_all_surfaces_port = dev_ext->io_port + QXL_IO_DESTROY_ALL_SURFACES;
             driver_info->create_primary_port = dev_ext->io_port + QXL_IO_CREATE_PRIMARY;
             driver_info->destroy_primary_port = dev_ext->io_port + QXL_IO_DESTROY_PRIMARY;
+            driver_info->memslot_add_port = dev_ext->io_port + QXL_IO_MEMSLOT_ADD;
+            driver_info->memslot_del_port = dev_ext->io_port + QXL_IO_MEMSLOT_DEL;
 
             driver_info->primary_surface_create = &dev_ext->ram_header->create_surface;
 
+            driver_info->n_surfaces = dev_ext->rom->n_surfaces;
+
+	    driver_info->fb_phys = dev_ext->vram_physical.QuadPart;
+
             driver_info->dev_id = dev_ext->rom->id;
         }
         break;


More information about the Spice-commits mailing list