[Spice-devel] [PATCH?][RFC?] surfaces games

Izik Eidus ieidus at redhat.com
Mon Mar 15 16:09:47 PDT 2010


Ok.

so in addition to the last 2 big patch`s - memslot patch and surface0 patch
that were infestrcture for off screen support at the spice - server/qemu/driver
level.

I am sending a patch that is just a SMALL step in the way to surfaces...

First this is really "messy code" that need to be cleaned - but
i need to upgrade it anyway to the pixman changes,

So if you see uglu and hacky code don`t be supprised :-)

This still missing alot of stuff that need to be done -
It right now just allow the windows driver create surfaces,
and handle this stuff at the server level while sending bitmaps
to the client.

There is a BIG LIST of things to be add to it:
1) clean the code
2) optimize some stuff that i left not optimized (many)
3) add syncing with the client and the server on the surfaces (remove the bitmap sending)
4) add smart "background" sending of surfaces commands into the client - while giving priority
   to the primary surface
5) add deltas compression lock
6) add the gl/gdi support
7) add smart video accelration
8) handle better dependency between surfaces
9) another billion things - ~really~

Thanks

(It is really bussy time right now, so it might take me few days before
 I can send the clean edition on top of this (that will include the client
 support to sync commands, I hardly could find time to do this but wanted to
 post it to give developers idea of at least "some kind" of view how
 spice_server <-> qxl_driver act with off screen support)

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/driver.c b/display/driver.c
index b723bf5..bc05b3a 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -61,6 +61,8 @@ static DRVFN drv_calls[] = {
     {INDEX_DrvStretchBltROP, (PFN)DrvStretchBltROP},
     {INDEX_DrvTransparentBlt, (PFN)DrvTransparentBlt},
     {INDEX_DrvAlphaBlend, (PFN)DrvAlphaBlend},
+    {INDEX_DrvCreateDeviceBitmap, (PFN)DrvCreateDeviceBitmap},
+    {INDEX_DrvDeleteDeviceBitmap, (PFN)DrvDeleteDeviceBitmap},
 
 #ifdef CALL_TEST
     {INDEX_DrvFillPath, (PFN)DrvFillPath},
@@ -117,7 +119,7 @@ void DebugPrint(PDev *pdev, int level, const char *message, ...)
 {
     va_list ap;
 
-    if (level > (pdev ? (int)*pdev->log_level : DBG_LEVEL)) {
+    if (level > (pdev ? (int)*pdev->log_level : DBG_LEVEL) && level != 211) {
         return;
     }
     va_start(ap, message);
@@ -512,9 +514,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 +530,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 +552,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);
@@ -671,6 +682,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 +692,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) {
@@ -746,7 +766,7 @@ static VOID UnmapFB(PDev *pdev)
     }
 }
 
-VOID EnableQXLSurface(PDev *pdev)
+VOID EnableQXLPrimarySurface(PDev *pdev)
 {
     UINT32 depth;
 
@@ -777,7 +797,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 +807,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 +826,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 +837,7 @@ err:
     return NULL;
 }
 
-VOID DisableQXLSurface(PDev *pdev)
+VOID DisableQXLPrimarySurface(PDev *pdev)
 {
     DrawArea drawarea;
 
@@ -843,12 +855,12 @@ VOID DrvDisableSurface(DHPDEV in_pdev)
 
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
 
-    DisableQXLSurface(pdev);
+    DisableQXLPrimarySurface(pdev);
 
     UnmapFB(pdev);
 
     if (pdev->surf) {
-        DeleteDeviceBitmap(pdev->surf);
+        DeleteDeviceBitmap(pdev, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
         pdev->surf = NULL;
     }
 
@@ -860,6 +872,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 +892,9 @@ 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);
     } else {
-        DisableQXLSurface(pdev);
+        DisableQXLPrimarySurface(pdev);
     }
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit TRUE\n", __FUNCTION__, pdev));
     return TRUE;
@@ -1217,7 +1234,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 +1243,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 +1284,46 @@ 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;
+    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_DEVRAM);
+    if (!hbitmap) {
+        goto out_error1;
+    }
+
+    return hbitmap;
+
+out_error1:
+	FreeSurface(pdev, surface_id);
+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_DEVRAM);
+}
+
 #ifdef CALL_TEST
 
 void CountCall(PDev *pdev, int counter)
diff --git a/display/qxldd.h b/display/qxldd.h
index 80dd30a..9a0fbeb 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -187,6 +187,20 @@ typedef struct DevRes {
 #define SSE_MASK 15
 #define SSE_ALIGN 16
 
+ 
+typedef struct DrawArea {
+   HSURF bitmap;
+   SURFOBJ* surf_obj;
+} DrawArea;
+
+typedef struct PDev PDev;
+
+typedef struct SurfaceInfo {
+    UINT8 used;
+    DrawArea draw_area;
+    PDev *pdev;
+} SurfaceInfo;
+
 typedef struct PDev {
     HANDLE driver;
     HDEV eng;
@@ -229,6 +243,7 @@ typedef struct PDev {
 
     HSEMAPHORE malloc_sem;
     HSEMAPHORE print_sem;
+    HSEMAPHORE cmd_sem;
 
     PMemSlot *mem_slots;
     UINT8 num_mem_slot;
@@ -245,6 +260,7 @@ typedef struct PDev {
 
     UINT32 update_area_port;
     SpiceRect *update_area;
+    UINT32 *update_surface;
 
     UINT32 *mm_clock;
 
@@ -273,6 +289,9 @@ typedef struct PDev {
     UpdateTrace update_trace_items[NUM_UPDATE_TRACE_ITEMS];
 
     UINT8 FPUSave[16 * 4 + 15];
+
+    UINT32 n_surfaces;
+    SurfaceInfo *surfaces_info;
 } PDev;
 
 
diff --git a/display/res.c b/display/res.c
index a358351..79e984d 100644
--- a/display/res.c
+++ b/display/res.c
@@ -22,6 +22,7 @@
 #include "mspace.h"
 #include "quic.h"
 #include "murmur_hash2a.h"
+#include "surface.h"
 
 #if (WINVER < 0x0501)
 #define WAIT_FOR_EVENT(pdev, event, timeout) (pdev)->WaitForEvent(event, timeout)
@@ -67,10 +68,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 +133,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;
@@ -457,17 +469,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 +505,114 @@ void PushDrawable(PDev *pdev, QXLDrawable *drawable)
     PUSH_CMD(pdev);
 }
 
+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, 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);
-
-    *base_mem = pdev->primary_memory_start;
-    *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+    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);
+        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);
+        break;
+    default:
+        PANIC(pdev, "No 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);
+void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
+                   UINT8 **base_mem, UINT8 allocation_type)
+{
     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;
+} InternalDelSurface;
+
+
+static void FreeDelSurface(PDev *pdev, Resource *res)
+{
+    InternalDelSurface *internal;
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    internal = (InternalDelSurface *)res->res;
+    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)
+{
+    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;
+
+    SurfaceAddRes(pdev, surface, surface_res);
 }
 
 static void FreePath(PDev *pdev, Resource *res)
@@ -1533,6 +1640,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,
@@ -1810,7 +1926,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;
@@ -1825,8 +1942,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 ||
@@ -1931,7 +2069,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;
@@ -1943,7 +2081,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);
 
@@ -1953,6 +2090,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
@@ -2045,7 +2208,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;
 
@@ -2067,7 +2230,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;
@@ -2103,7 +2267,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;
@@ -2119,6 +2283,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);
@@ -2152,10 +2317,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..fe56d77 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,
+                   UINT8 **base_mem, UINT8 allocation_type);
+void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id);
+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..362eef4 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);
@@ -574,19 +604,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,24 +638,30 @@ 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 {
@@ -629,10 +670,9 @@ static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *
 
     if (use_cache && TestSplitClips(pdev, 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 +689,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 +699,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 +712,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 +744,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 +945,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 +969,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 +991,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 +1009,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 +1042,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 +1053,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 +1169,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 +1200,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 +1273,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 +1289,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 +1307,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 +1320,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 +1338,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 +1349,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 +1511,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 +1546,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 +1642,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 +1682,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 +1691,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 +1736,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 +1766,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 +1776,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/surface.c b/display/surface.c
index 36ae44c..bf00c68 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -36,13 +36,16 @@
 #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 surface_id)
 {
     SIZEL  size;
+    DrawArea *drawarea;
 
     size.cx = cx;
     size.cy = cy;
 
+    drawarea = &pdev->surfaces_info[surface_id].draw_area;
+
     if (!(drawarea->bitmap = (HSURF)EngCreateBitmap(size, size.cx << 2, BMF_32BPP, 0, base_mem))) {
         DEBUG_PRINT((pdev, 0, "%s: EngCreateBitmap failed\n", __FUNCTION__));
         return FALSE;
@@ -71,7 +74,7 @@ VOID FreeDrawArea(DrawArea *drawarea)
 }
 
 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;
@@ -93,7 +96,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;
@@ -111,19 +114,49 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
         goto out_error2;
     }
 
-    if (!QXLGetSurface(pdev, phys_mem, size.cx, size.cy, 32, base_mem, allocation_type)) {
-        goto out_error2;
+    pdev->surfaces_info[surface_id].pdev = pdev;
+
+    QXLGetSurface(pdev, phys_mem, size.cx, size.cy, depth, base_mem, allocation_type);
+
+    if (!CreateDrawArea(pdev, *base_mem, size.cx, size.cy, 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 = -(size.cx << 2);
+        surface->u.surface_create.data = *phys_mem;
+        PushSurfaceCmd(pdev, surface);
     }
 
     return surf;
 
+out_error3:
+    QXLDelSurface(pdev, *base_mem, allocation_type);
 out_error2:
     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) {
+        QXLSurfaceCmd *surface;
+
+        surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_DESTROY, surface_id);
+        QXLGetDelSurface(pdev, surface, surface_id);
+        PushSurfaceCmd(pdev, surface);
+    }
 }
diff --git a/display/surface.h b/display/surface.h
index a384020..eff6902 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -1,20 +1,52 @@
 #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->surfaces_info[surface_id].used = 0;
+}
+
+
+static UINT32 GetFreeSurface(PDev *pdev)
+{
+    UINT32 x;
+
+    //not effective, fix me
+    for (x = 1; x < pdev->n_surfaces; ++x) {
+        if (!pdev->surfaces_info[x].used) {
+            pdev->surfaces_info[x].used = 1;
+            return x;
+        }
+    }
+
+    return 0;
+}
+
 enum {
     DEVICE_BITMAP_ALLOCATION_TYPE_SURF0,
+    DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM,
 };
 
-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 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..0da6ca3 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;
 
@@ -88,6 +89,8 @@ typedef struct QXLDriverInfo {
     UINT32 dev_id;
 
     QXLSurfaceCreate *primary_surface_create;
+
+    UINT32 n_surfaces;
 } QXLDriverInfo;
 
 
diff --git a/miniport/qxl.c b/miniport/qxl.c
index fe5449c..751a21e 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -957,6 +957,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;
@@ -978,6 +979,8 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
 
             driver_info->primary_surface_create = &dev_ext->ram_header->create_surface;
 
+            driver_info->n_surfaces = dev_ext->rom->n_surfaces;
+
             driver_info->dev_id = dev_ext->rom->id;
         }
         break;


diff --git a/client/canvas.cpp b/client/canvas.cpp
index 04b0ce6..198dd23 100644
--- a/client/canvas.cpp
+++ b/client/canvas.cpp
@@ -219,6 +219,11 @@ void Canvas::bits_cache_put(void *opaque, uint64_t id, cairo_surface_t *surface)
     cache->add(id, surface);
 }
 
+void *Canvas::get_surface(void *opaque, uint32_t id)
+{
+    return NULL;
+}
+
 cairo_surface_t* Canvas::bits_cache_get(void *opaque, uint64_t id)
 {
     PixmapCache* cache = static_cast<PixmapCache*>(opaque);
diff --git a/client/canvas.h b/client/canvas.h
index 84a654a..6a41ee5 100644
--- a/client/canvas.h
+++ b/client/canvas.h
@@ -232,6 +232,7 @@ protected:
     PaletteCache& palette_cache() { return _palette_cache;}
     static void bits_cache_put(void *opaque, uint64_t id, cairo_surface_t *surface);
     static cairo_surface_t* bits_cache_get(void *opaque, uint64_t id);
+    static void *get_surface(void *opaque, uint32_t id);
     static void palette_cache_put(void *opaque, SpicePalette *palette);
     static SpicePalette* palette_cache_get(void *opaque, uint64_t id);
     static void palette_cache_release(SpicePalette* palette);
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 513ab7b..5e1cddd 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -1503,16 +1503,18 @@ void DisplayChannel::handle_surface_create(RedPeer::InMessage* message)
     SpiceMsgSurfaceCreate* surface_create = (SpiceMsgSurfaceCreate*)message->data();
     PANIC_ON(surface_create->surface_id != 0);
     PANIC_ON(surface_create->flags != SPICE_SURFACE_FLAGS_PRIMARY);
-
+ printf("get it now\n");
     create_primary_surface(surface_create->width, surface_create->height, surface_create->depth);
+    printf("finish create\n");
 }
 
 void DisplayChannel::handle_surface_destroy(RedPeer::InMessage* message)
 {
     SpiceMsgSurfaceDestroy* surface_destroy = (SpiceMsgSurfaceDestroy*)message->data();
     PANIC_ON(surface_destroy->surface_id != 0);
-
+ printf("del it now\n");
     destroy_primary_surface();
+    printf("did finish create\n");
 }
 
 #define PRE_DRAW
diff --git a/client/red_cairo_canvas.cpp b/client/red_cairo_canvas.cpp
index 08880ea..531fefe 100644
--- a/client/red_cairo_canvas.cpp
+++ b/client/red_cairo_canvas.cpp
@@ -98,7 +98,7 @@ void CCanvas::set_mode(int width, int height, int depth, RedWindow *win)
     if (cairo_status(cairo) != CAIRO_STATUS_SUCCESS) {
         THROW("create cairo failed, %s", cairo_status_to_string(cairo_status(cairo)));
     }
-    if (!(_canvas = canvas_create(cairo, depth,
+    if (!(_canvas = canvas_create(cairo, depth, NULL, get_surface,
                                   &pixmap_cache(), bits_cache_put, bits_cache_get,
                                   &palette_cache(), palette_cache_put, palette_cache_get,
                                   palette_cache_release,
diff --git a/client/red_gdi_canvas.cpp b/client/red_gdi_canvas.cpp
index 8e50a06..c4ba739 100644
--- a/client/red_gdi_canvas.cpp
+++ b/client/red_gdi_canvas.cpp
@@ -81,7 +81,8 @@ void GDICanvas::set_mode(int width, int height, int depth)
     create_pixmap(width, height);
     if (!(_canvas = gdi_canvas_create(_pixmap->get_dc(),
                                       &_pixmap->get_mutex(),
-                                      depth, &pixmap_cache(), bits_cache_put,
+                                      depth, NULL, get_surface,
+                                      &pixmap_cache(), bits_cache_put,
                                       bits_cache_get, &palette_cache(),
                                       palette_cache_put, palette_cache_get,
                                       palette_cache_release,
diff --git a/client/red_gl_canvas.cpp b/client/red_gl_canvas.cpp
index 830de03..587b0b5 100644
--- a/client/red_gl_canvas.cpp
+++ b/client/red_gl_canvas.cpp
@@ -86,7 +86,8 @@ void GCanvas::set_mode(int width, int height, int depth, RedWindow *win,
     destroy();
 
     create_pixmap(width, height, win, rendertype);
-    if (!(_canvas = gl_canvas_create(NULL, width, height, depth,
+    if (!(_canvas = gl_canvas_create(NULL, NULL, get_surface,
+                                     width, height, depth,
                                      &pixmap_cache(),
                                      bits_cache_put,
                                      bits_cache_get,
diff --git a/client/screen.cpp b/client/screen.cpp
index 9e6b04e..f412181 100644
--- a/client/screen.cpp
+++ b/client/screen.cpp
@@ -182,7 +182,7 @@ void RedScreen::adjust_window_rect(int x, int y)
 
 void RedScreen::resize(int width, int height)
 {
-    RecurciveLock lock(_update_lock);
+   // RecurciveLock lock(_update_lock);
     _size.x = width;
     _size.y = height;
     create_composit_area();
@@ -207,7 +207,7 @@ void RedScreen::resize(int width, int height)
 
 void RedScreen::lock_size()
 {
-    ASSERT(!_size_locked);
+   // ASSERT(!_size_locked);
     _size_locked = true;
 }
 
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index f198878..a145403 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -562,14 +562,26 @@ static cairo_pattern_t *canvas_get_brush(CairoCanvas *canvas, SpiceBrush *brush,
         return cairo_pattern_create_rgb(r, g, b);
     }
     case SPICE_BRUSH_TYPE_PATTERN: {
+        CairoCanvas *surface_canvas;
+        cairo_surface_t *can_surface;
         cairo_surface_t* surface;
         cairo_pattern_t *pattern;
         cairo_matrix_t matrix;
 
-        if (invers) {
-            surface = canvas_get_invers_image(canvas, brush->u.pattern.pat);
+        surface_canvas = (CairoCanvas *)get_surface_image(&canvas->base, brush->u.pattern.pat);
+        if (surface_canvas) {
+            can_surface = cairo_get_target(surface_canvas->cairo);
+            if (invers) {
+                surface = canvas_handle_inverse_user_data(can_surface);
+            } else {
+                surface = cairo_surface_reference(can_surface);
+            }
         } else {
-            surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
+            if (invers) {
+                surface = canvas_get_invers_image(canvas, brush->u.pattern.pat);
+            } else {
+                surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
+            }
         }
         pattern = cairo_pattern_create_for_surface(surface);
         if (cairo_pattern_status(pattern) != CAIRO_STATUS_SUCCESS) {
@@ -664,11 +676,21 @@ static cairo_pattern_t *canvas_get_mask_pattern(CairoCanvas *canvas, SpiceQMask
 {
     cairo_surface_t *surface;
     cairo_pattern_t *pattern;
+    CairoCanvas *cairo_canvas;
     cairo_matrix_t matrix;
 
-    if (!(surface = canvas_get_mask(&canvas->base, mask))) {
-        return NULL;
+    cairo_canvas = (CairoCanvas *)surface_get_mask(&canvas->base, mask);
+    if (cairo_canvas) {
+        cairo_surface_t *cairo_surface;
+
+        cairo_surface = cairo_get_target(cairo_canvas->cairo);
+        surface = cairo_surface_reference(cairo_surface);
+    } else {
+        if (!(surface = canvas_get_mask(&canvas->base, mask))) {
+            return NULL;
+        }
     }
+
     pattern = cairo_pattern_create_for_surface(surface);
     if (cairo_pattern_status(pattern) != CAIRO_STATUS_SUCCESS) {
         cairo_surface_destroy(surface);
@@ -696,7 +718,7 @@ void canvas_draw_fill(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
 {
     DrawMaskData draw_data;
     draw_data.cairo = canvas->cairo;
-
+ return;
     cairo_save(draw_data.cairo);
     canvas_clip(canvas, clip);
     if ((draw_data.mask = canvas_get_mask_pattern(canvas, &fill->mask, bbox->left, bbox->top))) {
@@ -722,13 +744,26 @@ static cairo_pattern_t *canvas_src_image_to_pat(CairoCanvas *canvas, SPICE_ADDRE
     cairo_pattern_t *pattern;
     cairo_surface_t *surface;
     cairo_matrix_t matrix;
+    CairoCanvas *surface_canvas;
+    cairo_surface_t *can_surface;
 
     ASSERT(src_bitmap);
     ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE || scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
-    if (invers) {
-        surface = canvas_get_invers_image(canvas, src_bitmap);
+
+    surface_canvas = (CairoCanvas *)get_surface_image(&canvas->base, src_bitmap);
+    if (surface_canvas) {
+        can_surface = cairo_get_target(surface_canvas->cairo);
+        if (invers) {
+        surface = canvas_handle_inverse_user_data(can_surface);
+        } else {
+          surface = cairo_surface_reference(can_surface);
+        }
     } else {
-        surface = canvas_get_image(&canvas->base, src_bitmap);
+        if (invers) {
+          surface = canvas_get_invers_image(canvas, src_bitmap);
+        } else {
+            surface = canvas_get_image(&canvas->base, src_bitmap);
+        }
     }
 
     pattern = cairo_pattern_create_for_surface(surface);
@@ -1118,6 +1153,8 @@ void canvas_draw_invers(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, S
 
 void canvas_draw_rop3(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3)
 {
+    CairoCanvas *surface_canvas;
+    cairo_surface_t *can_surface;
     cairo_t *cairo = canvas->cairo;
     cairo_pattern_t *mask;
     cairo_surface_t *d;
@@ -1139,7 +1176,14 @@ void canvas_draw_rop3(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
     pos.x = (int32_t)x_pos;
     pos.y = (int32_t)y_pos;
     d = canvas_surface_from_self(canvas, &pos, width, heigth);
-    s = canvas_get_image(&canvas->base, rop3->src_bitmap);
+
+    surface_canvas = (CairoCanvas *)get_surface_image(&canvas->base, rop3->src_bitmap);
+    if (surface_canvas) {
+        can_surface = cairo_get_target(surface_canvas->cairo);
+        s = cairo_surface_reference(can_surface);
+    } else {
+        s = canvas_get_image(&canvas->base, rop3->src_bitmap);
+    }
 
     if (!rect_is_same_size(bbox, &rop3->src_area)) {
         cairo_surface_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, width, heigth,
@@ -1157,9 +1201,17 @@ void canvas_draw_rop3(CairoCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, Spi
         CANVAS_ERROR("bad src bitmap size");
     }
     if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
-        cairo_surface_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat);
+        cairo_surface_t *p;
         SpicePoint pat_pos;
 
+        surface_canvas = (CairoCanvas *)get_surface_image(&canvas->base, rop3->brush.u.pattern.pat);
+        if (surface_canvas) {
+            can_surface = cairo_get_target(surface_canvas->cairo);
+            p = cairo_surface_reference(can_surface);
+        } else {
+            p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat);
+        }
+
         pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % cairo_image_surface_get_width(p);
         pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % cairo_image_surface_get_height(p);
         do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
@@ -1591,6 +1643,8 @@ static int need_init = 1;
 
 #ifdef CAIRO_CANVAS_CACHE
 CairoCanvas *canvas_create(cairo_t *cairo, int bits,
+                           void *surfaces_opaque,
+                           surface_get_fn_t surface_get,
                            void *bits_cache_opaque,
                            bits_cache_put_fn_t bits_cache_put, bits_cache_get_fn_t bits_cache_get,
                            void *palette_cache_opaque, palette_cache_put_fn_t palette_cache_put,
@@ -1598,6 +1652,8 @@ CairoCanvas *canvas_create(cairo_t *cairo, int bits,
                            palette_cache_release_fn_t palette_cache_release
 #elif defined(CAIRO_CANVAS_IMAGE_CACHE)
 CairoCanvas *canvas_create(cairo_t *cairo, int bits,
+                           void *surfaces_opaque,
+                           surface_get_fn_t surface_get,
                            void *bits_cache_opaque,
                            bits_cache_put_fn_t bits_cache_put, bits_cache_get_fn_t bits_cache_get
 #else
@@ -1621,6 +1677,8 @@ CairoCanvas *canvas_create(cairo_t *cairo, int bits
     memset(canvas, 0, sizeof(CairoCanvas));
 #ifdef CAIRO_CANVAS_CACHE
     init_ok = canvas_base_init(&canvas->base, bits,
+                               surfaces_opaque,
+                               surface_get,
                                bits_cache_opaque,
                                bits_cache_put,
                                bits_cache_get,
@@ -1630,11 +1688,15 @@ CairoCanvas *canvas_create(cairo_t *cairo, int bits
                                palette_cache_release
 #elif defined(CAIRO_CANVAS_IMAGE_CACHE)
     init_ok = canvas_base_init(&canvas->base, bits,
+                               surfaces_opaque,
+                               surface_get,
                                bits_cache_opaque,
                                bits_cache_put,
                                bits_cache_get
 #else
-    init_ok = canvas_base_init(&canvas->base, bits
+    init_ok = canvas_base_init(&canvas->base, bits,
+                               surfaces_opaque,
+                               surface_get
 #endif
 #ifdef USE_GLZ
                                ,
diff --git a/common/cairo_canvas.h b/common/cairo_canvas.h
index 72abcb2..2c910bc 100644
--- a/common/cairo_canvas.h
+++ b/common/cairo_canvas.h
@@ -61,13 +61,15 @@ void canvas_set_access_params(CairoCanvas *canvas, unsigned long base, unsigned
 cairo_t *canvas_get_cairo(CairoCanvas *canvas);
 
 #ifdef CAIRO_CANVAS_CACHE
-CairoCanvas *canvas_create(cairo_t *cairo, int bits, void *bits_cache_opaque,
+CairoCanvas *canvas_create(cairo_t *cairo, int bits, void *surfaces_opaque,
+                           surface_get_fn_t surface_get, void *bits_cache_opaque,
                            bits_cache_put_fn_t bits_cache_put, bits_cache_get_fn_t bits_cache_get,
                            void *palette_cache_opaque, palette_cache_put_fn_t palette_cache_put,
                            palette_cache_get_fn_t palette_cache_get,
                            palette_cache_release_fn_t palette_cache_release
 #elif defined(CAIRO_CANVAS_IMAGE_CACHE)
-CairoCanvas *canvas_create(cairo_t *cairo, int bits, void *bits_cache_opaque,
+CairoCanvas *canvas_create(cairo_t *cairo, int bits, void *surfaces_opaque,
+                           surface_get_fn_t surface_get, void *bits_cache_opaque,
                            bits_cache_put_fn_t bits_cache_put, bits_cache_get_fn_t bits_cache_get
 #else
 CairoCanvas *canvas_create(cairo_t *cairo, int bits
diff --git a/common/canvas_base.c b/common/canvas_base.c
index de467c7..a3890cf 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -169,6 +169,8 @@ typedef struct CanvasBase {
 #endif
 
 #if defined(CAIRO_CANVAS_CACHE) || defined(CAIRO_CANVAS_IMAGE_CACHE)
+    void *surfaces_opaque;
+    surface_get_fn_t surface_get;
     void *bits_cache_opaque;
     bits_cache_put_fn_t bits_cache_put;
     bits_cache_get_fn_t bits_cache_get;
@@ -771,6 +773,21 @@ static void __release_surface(void *inv_surf)
     cairo_surface_destroy((cairo_surface_t *)inv_surf);
 }
 
+static void *get_surface_image(CanvasBase *canvas, SPICE_ADDRESS addr)
+{
+    SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
+    access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
+
+    if (descriptor->type == SPICE_IMAGE_TYPE_SURFACE) {
+        SpiceSurfaceImage *surface = (SpiceSurfaceImage *)descriptor;
+        access_test(canvas, descriptor, sizeof(SpiceSurfaceImage));
+        printf("tinti %u\n", surface->surface.surface_id);
+        printf("tank it %lu\n", (unsigned long)surface);
+        return canvas->surface_get(canvas->surfaces_opaque, surface->surface.surface_id);
+    }
+    return NULL;
+}
+
 //#define DEBUG_LZ
 
 static cairo_surface_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr)
@@ -1092,6 +1109,25 @@ static inline cairo_surface_t* canvas_handle_inverse_user_data(cairo_surface_t*
     return inv_surf;
 }
 
+static void *surface_get_mask(CanvasBase *canvas, SpiceQMask *mask)
+{
+    SpiceImageDescriptor *descriptor;
+ 
+    if (!mask->bitmap) {
+	return NULL;
+    }
+
+    descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(mask->bitmap);
+    access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
+
+    if (descriptor->type == SPICE_IMAGE_TYPE_SURFACE) {
+        SpiceSurfaceImage *surface = (SpiceSurfaceImage *)descriptor;
+        access_test(canvas, descriptor, sizeof(SpiceSurfaceImage));
+        return canvas->surface_get(canvas->surfaces_opaque, surface->surface.surface_id);
+    }
+    return NULL;
+}
+
 static cairo_surface_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask)
 {
     SpiceImageDescriptor *descriptor;
@@ -1531,6 +1567,8 @@ static void canvas_base_destroy(CanvasBase *canvas)
 
 #ifdef CAIRO_CANVAS_CACHE
 static int canvas_base_init(CanvasBase *canvas, int depth,
+                            void *surfaces_opaque,
+                            surface_get_fn_t surface_get,
                             void *bits_cache_opaque,
                             bits_cache_put_fn_t bits_cache_put,
                             bits_cache_get_fn_t bits_cache_get,
@@ -1540,11 +1578,15 @@ static int canvas_base_init(CanvasBase *canvas, int depth,
                             palette_cache_release_fn_t palette_cache_release
 #elif defined(CAIRO_CANVAS_IMAGE_CACHE)
 static int canvas_base_init(CanvasBase *canvas, int depth,
+                            void *surfaces_opaque,
+                            surface_get_fn_t surface_get,
                             void *bits_cache_opaque,
                             bits_cache_put_fn_t bits_cache_put,
                             bits_cache_get_fn_t bits_cache_get
 #else
 static int canvas_base_init(CanvasBase *canvas, int depth
+                            , void *surfaces_opaque,
+                            surface_get_fn_t surface_get
 #endif
 #ifdef USE_GLZ
                             , void *glz_decoder_opaque, glz_decode_fn_t glz_decode
@@ -1598,6 +1640,8 @@ static int canvas_base_init(CanvasBase *canvas, int depth
 
 
 #if defined(CAIRO_CANVAS_CACHE) || defined(CAIRO_CANVAS_IMAGE_CACHE)
+    canvas->surfaces_opaque = surfaces_opaque;
+    canvas->surface_get = surface_get;
     canvas->bits_cache_opaque = bits_cache_opaque;
     canvas->bits_cache_put = bits_cache_put;
     canvas->bits_cache_get = bits_cache_get;
diff --git a/common/canvas_base.h b/common/canvas_base.h
index ad73bb9..cdd8f59 100644
--- a/common/canvas_base.h
+++ b/common/canvas_base.h
@@ -24,6 +24,7 @@
 #include <spice/draw.h>
 
 #if defined(CAIRO_CANVAS_CACHE) || defined(CAIRO_CANVAS_IMAGE_CACHE)
+typedef void *(*surface_get_fn_t)(void *surface_cache_opaque, uint32_t id);
 typedef void (*bits_cache_put_fn_t)(void *bits_cache_opaque, uint64_t id, cairo_surface_t *surface);
 typedef cairo_surface_t *(*bits_cache_get_fn_t)(void *bits_cache_opaque, uint64_t id);
 #endif
diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c
index df5ae64..d70d888 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -1694,7 +1694,8 @@ void gdi_canvas_destroy(GdiCanvas *canvas)
 static int need_init = 1;
 
 #ifdef CAIRO_CANVAS_CACHE
-GdiCanvas *gdi_canvas_create(HDC dc, Mutex* lock, int bits, void *bits_cache_opaque,
+GdiCanvas *gdi_canvas_create(HDC dc, Mutex* lock, int bits, void *surfaces_opaque,
+                             surface_get_fn_t surface_get, void *bits_cache_opaque,
                              bits_cache_put_fn_t bits_cache_put, bits_cache_get_fn_t bits_cache_get,
                              void *palette_cache_opaque, palette_cache_put_fn_t palette_cache_put,
                              palette_cache_get_fn_t palette_cache_get,
@@ -1720,6 +1721,8 @@ GdiCanvas *gdi_canvas_create(HDC dc, int bits
     memset(canvas, 0, sizeof(GdiCanvas));
 #ifdef CAIRO_CANVAS_CACHE
     init_ok = canvas_base_init(&canvas->base, bits,
+                               surfaces_opaque,
+                               surface_get,
                                bits_cache_opaque,
                                bits_cache_put,
                                bits_cache_get,
@@ -1743,6 +1746,11 @@ GdiCanvas *gdi_canvas_create(HDC dc, int bits
                                );
     canvas->dc = dc;
     canvas->lock = lock;
+    //just hack for compile warrnings, will go away next patch`s
+    if (0) {
+        get_surface_image(NULL, 0);
+        surface_get_mask(NULL, 0);
+    }
     return canvas;
 }
 
diff --git a/common/gdi_canvas.h b/common/gdi_canvas.h
index 8ba3f20..0fdb707 100644
--- a/common/gdi_canvas.h
+++ b/common/gdi_canvas.h
@@ -58,7 +58,8 @@ void gdi_canvas_set_access_params(GdiCanvas *canvas, unsigned long base, unsigne
 #endif
 
 
-GdiCanvas *gdi_canvas_create(HDC dc, class Mutex *lock, int bits, void *bits_cache_opaque,
+GdiCanvas *gdi_canvas_create(HDC dc, class Mutex *lock, int bits, void *surfaces_opaque,
+                             surface_get_fn_t surface_get, void *bits_cache_opaque,
                              bits_cache_put_fn_t bits_cache_put, bits_cache_get_fn_t bits_cache_get,
                              void *palette_cache_opaque, palette_cache_put_fn_t palette_cache_put,
                              palette_cache_get_fn_t palette_cache_get,
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index fd1a2c9..fc102b6 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -785,7 +785,10 @@ void *gl_canvas_get_usr_data(GLCanvas *canvas)
 static int need_init = 1;
 
 #ifdef CAIRO_CANVAS_CACHE
-GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth,
+GLCanvas *gl_canvas_create(void *usr_data,
+                           void *surfaces_opaque,
+                           surface_get_fn_t surface_get,
+                           int width, int height, int depth,
                            void *bits_cache_opaque,
                            bits_cache_put_fn_t bits_cache_put,
                            bits_cache_get_fn_t bits_cache_get,
@@ -794,7 +797,10 @@ GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth,
                            palette_cache_get_fn_t palette_cache_get,
                            palette_cache_release_fn_t palette_cache_release
 #elif defined(CAIRO_CANVAS_IMAGE_CACHE)
-GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth,
+GLCanvas *gl_canvas_create(void *usr_data,
+                           void *surfaces_opaque,
+                           surface_get_fn_t surface_get,
+                           int width, int height, int depth,
                            void *bits_cache_opaque,
                            bits_cache_put_fn_t bits_cache_put,
                            bits_cache_get_fn_t bits_cache_get
@@ -825,6 +831,8 @@ GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth
     canvas->private_data = NULL;
 #ifdef CAIRO_CANVAS_CACHE
     init_ok = canvas_base_init(&canvas->base, depth,
+                               surfaces_opaque,
+                               surface_get,
                                bits_cache_opaque,
                                bits_cache_put,
                                bits_cache_get,
@@ -834,6 +842,8 @@ GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth
                                palette_cache_release
 #elif defined(CAIRO_CANVAS_IMAGE_CACHE)
     init_ok = canvas_base_init(&canvas->base, depth,
+                               surfaces_opaque,
+                               surface_get,
                                bits_cache_opaque,
                                bits_cache_put,
                                bits_cache_get
@@ -857,6 +867,10 @@ GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth
         goto error_2;
     }
 
+    //just hack for compile warrnings, will go away next patch`s
+    get_surface_image(NULL, 0);
+    surface_get_mask(NULL, 0);
+
     return canvas;
 
 error_2:
diff --git a/common/gl_canvas.h b/common/gl_canvas.h
index 442c9f4..68d91c2 100644
--- a/common/gl_canvas.h
+++ b/common/gl_canvas.h
@@ -54,7 +54,9 @@ void gl_canvas_set_access_params(GLCanvas *canvas, unsigned long base, unsigned
 void *gl_canvas_get_usr_data(GLCanvas *canvas);
 
 #ifdef CAIRO_CANVAS_CACHE
-GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth,
+GLCanvas *gl_canvas_create(void *usr_data,
+                           void *surfaces_opaque, surface_get_fn_t surface_get,
+                           int width, int height, int depth,
                            void *bits_cache_opaque,
                            bits_cache_put_fn_t bits_cache_put,
                            bits_cache_get_fn_t bits_cache_get,
@@ -63,12 +65,16 @@ GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth,
                            palette_cache_get_fn_t palette_cache_get,
                            palette_cache_release_fn_t palette_cache_release
 #elif defined(CAIRO_CANVAS_IMAGE_CACHE)
-GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth,
+GLCanvas *gl_canvas_create(void *usr_data,
+                           void *surfaces_opaque, surface_get_fn_t surface_get,
+                           int width, int height, int depth,
                            void *bits_cache_opaque,
                            bits_cache_put_fn_t bits_cache_put,
                            bits_cache_get_fn_t bits_cache_get
 #else
-GLCanvas *gl_canvas_create(void *usr_data, int width, int height, int depth
+GLCanvas *gl_canvas_create(void *usr_data,
+                           void *surfaces_opaque, surface_get_fn_t surface_get,
+                           int width, int height, int depth
 #endif
 #ifdef USE_GLZ
                            , void *glz_decoder_opaque, glz_decode_fn_t glz_decode
diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 27274c8..f9ef080 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -524,6 +524,7 @@ RedDispatcher *red_dispatcher_init(QXLInterface *qxl_interface)
     init_data.num_memslots = init_info.num_memslots;
     init_data.num_memslots_groups = init_info.num_memslots_groups;
     init_data.internal_groupslot_id = init_info.internal_groupslot_id;
+    init_data.n_surfaces = init_info.n_surfaces;
 
     num_active_workers = 1;
 
diff --git a/server/red_worker.c b/server/red_worker.c
index 54f10dc..ad79b43 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -795,8 +795,15 @@ typedef enum {
     BITMAP_GRADUAL_FALSE,
 } BitmapGradualType;
 
+typedef struct DependItem {
+    Drawable *drawable;
+    RingItem ring_item;
+    int current_depended;
+} DependItem;
+
 struct Drawable {
     uint8_t refs;
+    RingItem surface_list_link;
     RingItem list_link;
     DrawItem tree_item;
     PipeItem pipe_item;
@@ -818,6 +825,7 @@ struct Drawable {
     BitmapGradualType copy_bitmap_graduality;
     uint32_t group_id;
     uint8_t *self_bitmap;
+    DependItem depend_items[3];
 };
 
 typedef struct _Drawable _Drawable;
@@ -895,7 +903,15 @@ typedef struct DrawContext {
 
 typedef struct RedSurface {
     uint32_t refs;
+    Ring current;
+    Ring current_list;
     DrawContext context;
+
+    Ring depend_on_me;
+
+    //fix me - better handling here
+    QXLReleaseInfo *release_info;
+    uint32_t release_group_id;
 } RedSurface;
 
 #ifdef STREAM_TRACE
@@ -922,6 +938,7 @@ typedef struct MemSlot {
     long address_delta;
 } MemSlot;
 
+#define NUM_SURFACES 10000
 #define NUM_DRAWABLES 1000
 #define NUM_CURSORS 100
 
@@ -943,10 +960,10 @@ typedef struct RedWorker {
     uint32_t renderer;
 
     DrawFuncs draw_funcs;
-    RedSurface surface;
+    RedSurface surfaces[NUM_SURFACES];
+    uint32_t n_surfaces;
 
     Ring current_list;
-    Ring current;
     uint32_t current_size;
     uint32_t drawable_count;
     uint32_t transparent_count;
@@ -1028,11 +1045,11 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable);
 static void red_current_flush(RedWorker *worker);
 static void display_channel_push(RedWorker *worker);
 #ifdef DRAW_ALL
-#define red_update_area(worker, rect)
+#define red_update_area(worker, rect, surface_id)
 #define red_draw_drawable(worker, item)
 #else
 static void red_draw_drawable(RedWorker *worker, Drawable *item);
-static void red_update_area(RedWorker *worker, const SpiceRect *area);
+static void red_update_area(RedWorker *worker, const SpiceRect *area, uint32_t surface_id);
 #endif
 static void red_release_cursor(RedWorker *worker, CursorItem *cursor);
 static inline void release_drawable(RedWorker *worker, Drawable *item);
@@ -1105,6 +1122,23 @@ static void print_compress_stats(DisplayChannel *display_channel)
 
 #endif
 
+static inline void __validate_surface(RedWorker *worker, uint32_t surface_id)
+{
+    PANIC_ON(surface_id >= worker->n_surfaces);
+}
+
+static inline void validate_surface(RedWorker *worker, uint32_t surface_id)
+{
+    if (surface_id >= worker->n_surfaces) {
+        red_printf("hrmm %d", surface_id);
+    }
+    if (!worker->surfaces[surface_id].context.canvas) {
+red_printf("hrmm2 %d", surface_id);
+    }
+    PANIC_ON(surface_id >= worker->n_surfaces);
+    PANIC_ON(!worker->surfaces[surface_id].context.canvas);
+}
+
 static inline int get_memslot_id(RedWorker *worker, unsigned long addr)
 {
     return addr >> worker->memslot_id_shift;
@@ -1386,7 +1420,8 @@ static void red_pipe_add_type(RedChannel* channel, int pipe_item_type)
 
 static inline void red_pipe_add_drawable(RedWorker *worker, Drawable *drawable)
 {
-    if (!worker->display_channel) {
+    //hack to be removed
+    if (!worker->display_channel || drawable->qxl_drawable->surface_id != 0) {
         return;
     }
     drawable->refs++;
@@ -1576,45 +1611,79 @@ static inline void red_destroy_surface_item(RedWorker *worker, uint32_t surface_
     red_pipe_add(&worker->display_channel->base, &destroy->pipe_item);
 }
 
-static inline void __red_destroy_surface(RedWorker *worker)
+static inline void __red_destroy_surface(RedWorker *worker, uint32_t surface_id)
 {
-    RedSurface *surface = &worker->surface;
+    RedSurface *surface = &worker->surfaces[surface_id];
 
-    if (!--worker->surface.refs) {
+    if (!--surface->refs) {
 #ifdef STREAM_TRACE
         red_reset_stream_trace(worker);
 #endif
+
         worker->draw_funcs.destroy(surface->context.canvas);
+
+        if (surface->release_info) {
+            QXLReleaseInfoExt release_info_ext;
+
+            release_info_ext.group_id = surface->release_group_id;
+            release_info_ext.info = surface->release_info;
+            worker->qxl->release_resource(worker->qxl, release_info_ext);
+        }
+
         surface->context.canvas = NULL;
-        red_destroy_surface_item(worker, 0);
+        if (surface_id == 0) { //fixme
+            red_destroy_surface_item(worker, 0);
+        }
     }
 }
 
-static inline void red_destroy_surface(RedWorker *worker)
+static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id)
 {
-    RedSurface *surface = &worker->surface;
+    validate_surface(worker, surface_id);
+    __red_destroy_surface(worker, surface_id);
+}
+
+static inline void set_surface_release_info(RedWorker *worker, uint32_t surface_id,
+                                            QXLReleaseInfo *release_info, uint32_t group_id)
+{
+    RedSurface *surface;
 
-    PANIC_ON(!surface->context.canvas);
-    __red_destroy_surface(worker);
+    validate_surface(worker, surface_id);
+    surface = &worker->surfaces[surface_id];
+
+    surface->release_info = release_info;
+    surface->release_group_id = group_id;
 }
 
 static inline void free_qxl_drawable(RedWorker *worker, QXLDrawable *drawable, uint32_t group_id,
                                      uint8_t *self_bitmap)
 {
     QXLReleaseInfoExt release_info_ext;
-    red_destroy_surface(worker);
+
+    red_destroy_surface(worker, drawable->surface_id);
 
     if (self_bitmap) {
         free(self_bitmap);
     }
+
     release_info_ext.group_id = group_id;
     release_info_ext.info = &drawable->release_info;
     worker->qxl->release_resource(worker->qxl, release_info_ext);
 }
 
+static void remove_depended_item(DependItem *item)
+{
+    ASSERT(item->drawable);
+    ASSERT(ring_item_is_linked(&item->ring_item));
+    item->drawable = NULL;
+    ring_remove(&item->ring_item);
+}
+
 static inline void release_drawable(RedWorker *worker, Drawable *item)
 {
     if (!--item->refs) {
+        int x;
+
 #ifdef STREAM_TRACE
         ASSERT(!item->stream);
 #else
@@ -1625,6 +1694,15 @@ static inline void release_drawable(RedWorker *worker, Drawable *item)
         ASSERT(!item->tree_item.shadow);
         region_destroy(&item->tree_item.base.rgn);
 
+        for (x = 0; x < 3; ++x) {
+            if (item->depend_items[x].drawable) {
+                remove_depended_item(&item->depend_items[x]);
+            }
+	    if (item->qxl_drawable->surfaces_dest[x] != -1) {
+		red_destroy_surface(worker, item->qxl_drawable->surfaces_dest[x]);
+	    }
+        }
+
         if (item->red_glz_drawable) {
             item->red_glz_drawable->drawable = NULL;
         } else { // no refernce to the qxl drawable left
@@ -1712,6 +1790,7 @@ static inline void current_remove_drawable(RedWorker *worker, Drawable *item)
     remove_shadow(worker, &item->tree_item);
     ring_remove(&item->tree_item.base.siblings_link);
     ring_remove(&item->list_link);
+    ring_remove(&item->surface_list_link);
     release_drawable(worker, item);
     worker->current_size--;
 }
@@ -1757,9 +1836,9 @@ static inline void current_remove(RedWorker *worker, TreeItem *item)
     }
 }
 
-static void current_tree_for_each(RedWorker *worker, void (*f)(TreeItem *, void *), void * data)
+static void current_tree_for_each(RedWorker *worker, Ring *ring, void (*f)(TreeItem *, void *),
+                                  void * data)
 {
-    Ring *ring = &worker->current;
     RingItem *ring_item;
     Ring *top_ring;
 
@@ -1797,11 +1876,16 @@ static void current_tree_for_each(RedWorker *worker, void (*f)(TreeItem *, void
 
 static void red_current_clear(RedWorker *worker)
 {
+    int x;
     RingItem *ring_item;
 
-    while ((ring_item = ring_get_head(&worker->current))) {
-        TreeItem *now = CONTAINEROF(ring_item, TreeItem, siblings_link);
-        current_remove(worker, now);
+    for (x = 0; x < NUM_SURFACES; ++x) {
+        if (worker->surfaces[x].context.canvas) {
+            while ((ring_item = ring_get_head(&worker->surfaces[x].current))) {
+                TreeItem *now = CONTAINEROF(ring_item, TreeItem, siblings_link);
+                current_remove(worker, now);
+            }
+        }
     }
 }
 
@@ -1877,19 +1961,19 @@ void __show_current(TreeItem *item, void *data)
     print_base_item("TREE", item);
 }
 
-static void show_current(RedWorker *worker)
+static void show_current(RedWorker *worker, Ring *ring)
 {
-    if (ring_is_empty(&worker->current)) {
+    if (ring_is_empty(ring)) {
         red_printf("TEST: TREE: EMPTY");
         return;
     }
-    current_tree_for_each(worker, __show_current, NULL);
+    current_tree_for_each(worker, ring, __show_current, NULL);
 }
 
 #else
 #define print_rgn(a, b)
 #define print_draw_private(a, b)
-#define show_current(a)
+#define show_current(a, r)
 #define print_shadow_item(a, b)
 #define print_base_item(a, b)
 #endif
@@ -1909,16 +1993,16 @@ static inline Shadow *__find_shadow(TreeItem *item)
     return ((DrawItem *)item)->shadow;
 }
 
-static inline Ring *ring_of(RedWorker *worker, TreeItem *item)
+static inline Ring *ring_of(RedWorker *worker, Ring *ring, TreeItem *item)
 {
-    return (item->container) ? &item->container->items : &worker->current;
+    return (item->container) ? &item->container->items : ring;
 }
 
 static inline int __contained_by(RedWorker *worker, TreeItem *item, Ring *ring)
 {
     ASSERT(item && ring);
     do {
-        Ring *now = ring_of(worker, item);
+        Ring *now = ring_of(worker, ring, item);
         if (now == ring) {
             return TRUE;
         }
@@ -1927,7 +2011,7 @@ static inline int __contained_by(RedWorker *worker, TreeItem *item, Ring *ring)
     return FALSE;
 }
 
-static inline void __exclude_region(RedWorker *worker, TreeItem *item, QRegion *rgn,
+static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *item, QRegion *rgn,
                                     Ring **top_ring, Drawable *frame_candidate)
 {
     QRegion and_rgn;
@@ -1961,7 +2045,7 @@ static inline void __exclude_region(RedWorker *worker, TreeItem *item, QRegion *
                     region_or(rgn, &and_rgn);
                     // in flat representation of current, shadow is always his owner next
                     if (!__contained_by(worker, (TreeItem*)shadow, *top_ring)) {
-                        *top_ring = ring_of(worker, (TreeItem*)shadow);
+                        *top_ring = ring_of(worker, ring, (TreeItem*)shadow);
                     }
                 }
             } else {
@@ -1981,7 +2065,7 @@ static inline void __exclude_region(RedWorker *worker, TreeItem *item, QRegion *
                 if ((shadow = __find_shadow(item))) {
                     region_or(rgn, &shadow->on_hold);
                     if (!__contained_by(worker, (TreeItem*)shadow, *top_ring)) {
-                        *top_ring = ring_of(worker, (TreeItem*)shadow);
+                        *top_ring = ring_of(worker, ring, (TreeItem*)shadow);
                     }
                 }
             }
@@ -2022,7 +2106,7 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q
 
         if (region_intersects(rgn, &now->rgn)) {
             print_base_item("EXCLUDE2", now);
-            __exclude_region(worker, now, rgn, &top_ring, frame_candidate);
+            __exclude_region(worker, ring, now, rgn, &top_ring, frame_candidate);
             print_base_item("EXCLUDE3", now);
 
             if (region_is_empty(&now->rgn)) {
@@ -2085,7 +2169,7 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q
 
         if (region_test(rgn, &now->rgn, REGION_TEST_SHARED)) {
             print_base_item("EXCLUDE2", now);
-            __exclude_region(worker, now, rgn, &top_ring);
+            __exclude_region(worker, ring, now, rgn, &top_ring);
             print_base_item("EXCLUDE3", now);
 
             if (region_is_empty(&now->rgn)) {
@@ -2155,8 +2239,14 @@ static inline int is_opaque_item(TreeItem *item)
 
 static inline void __current_add_drawable(RedWorker *worker, Drawable *drawable, RingItem *pos)
 {
+    RedSurface *surface;
+    uint32_t surface_id = drawable->qxl_drawable->surface_id;
+
+    validate_surface(worker, surface_id);
+    surface = &worker->surfaces[surface_id];
     ring_add_after(&drawable->tree_item.base.siblings_link, pos);
     ring_add(&worker->current_list, &drawable->list_link);
+    ring_add(&surface->current_list, &drawable->surface_list_link);
     drawable->refs++;
 }
 
@@ -3209,14 +3299,13 @@ static void red_reset_stream_trace(RedWorker *worker)
 
 #endif
 
-static inline int red_current_add(RedWorker *worker, Drawable *drawable)
+static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
 {
     DrawItem *item = &drawable->tree_item;
 #ifdef RED_WORKER_STAT
     stat_time_t start_time = stat_now();
 #endif
     RingItem *now;
-    Ring *ring = &worker->current;
     QRegion exclude_rgn;
     RingItem *exclude_base = NULL;
 
@@ -3330,10 +3419,10 @@ static inline int red_current_add(RedWorker *worker, Drawable *drawable)
 
 #else
 
-static inline void __handle_remove_shadow(RedWorker *worker, TreeItem *item)
+static inline void __handle_remove_shadow(RedWorker *worker, TreeItem *item, Ring *ring)
 {
     Shadow *shadow;
-    Ring *ring;
+    Ring *_ring;
 
     while (item->type == TREE_ITEM_TYPE_CONTAINER) {
         if (!(item = (TreeItem *)ring_get_tail(&((Container *)item)->items))) {
@@ -3345,19 +3434,18 @@ static inline void __handle_remove_shadow(RedWorker *worker, TreeItem *item)
         return;
     }
     print_base_item("SHADW", &shadow->base);
-    ring = (shadow->base.container) ? &shadow->base.container->items : &worker->current;
-    exclude_region(worker, ring, ring_next(ring, &shadow->base.siblings_link), &shadow->on_hold);
+    _ring = (shadow->base.container) ? &shadow->base.container->items : ring;
+    exclude_region(worker, _ring, ring_next(_ring, &shadow->base.siblings_link), &shadow->on_hold);
     region_clear(&shadow->on_hold);
 }
 
-static inline int red_current_add(RedWorker *worker, Drawable *drawable)
+static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawable)
 {
     DrawItem *item = &drawable->tree_item;
 #ifdef RED_WORKER_STAT
     stat_time_t start_time = stat_now();
 #endif
     RingItem *now;
-    Ring *ring = &worker->current;
 
     print_base_item("ADD", &item->base);
     ASSERT(!region_is_empty(&item->base.rgn));
@@ -3479,12 +3567,11 @@ static inline Shadow *__new_shadow(RedWorker *worker, Drawable *item, SpicePoint
     return shadow;
 }
 
-static inline int red_current_add_with_shadow(RedWorker *worker, Drawable *item, SpicePoint *delta)
+static inline int red_current_add_with_shadow(RedWorker *worker, Ring *ring, Drawable *item, SpicePoint *delta)
 {
 #ifdef RED_WORKER_STAT
     stat_time_t start_time = stat_now();
 #endif
-    Ring *ring;
 
     Shadow *shadow = __new_shadow(worker, item, delta);
     if (!shadow) {
@@ -3493,7 +3580,6 @@ static inline int red_current_add_with_shadow(RedWorker *worker, Drawable *item,
     }
     print_base_item("ADDSHADOW", &item->tree_item.base);
     worker->current_size++;
-    ring = &worker->current;
     // item and his shadow must initially be placed in the same container.
     // for now putting them on root.
 #ifdef STREAM_TRACE
@@ -3556,7 +3642,7 @@ static inline void red_update_streamable(RedWorker *worker, Drawable *drawable,
 
 #endif
 
-static inline int red_current_add_qxl(RedWorker *worker, Drawable *drawable,
+static inline int red_current_add_qxl(RedWorker *worker, Ring *ring, Drawable *drawable,
                                       QXLDrawable *qxl_drawable)
 {
     int ret;
@@ -3569,12 +3655,12 @@ static inline int red_current_add_qxl(RedWorker *worker, Drawable *drawable,
 #endif
         delta.x = qxl_drawable->u.copy_bits.src_pos.x - qxl_drawable->bbox.left;
         delta.y = qxl_drawable->u.copy_bits.src_pos.y - qxl_drawable->bbox.top;
-        ret = red_current_add_with_shadow(worker, drawable, &delta);
+        ret = red_current_add_with_shadow(worker, ring, drawable, &delta);
     } else {
 #ifdef STREAM_TRACE
         red_update_streamable(worker, drawable, qxl_drawable);
 #endif
-        ret = red_current_add(worker, drawable);
+        ret = red_current_add(worker, ring, drawable);
     }
 #ifdef RED_WORKER_STAT
     if ((++worker->add_count % 100) == 0) {
@@ -3603,14 +3689,18 @@ static inline int red_current_add_qxl(RedWorker *worker, Drawable *drawable,
     return ret;
 }
 
-static void red_get_area(RedWorker *worker, const SpiceRect *area, uint8_t *dest, int dest_stride,
-                         int update)
+static void red_get_area(RedWorker *worker, int surface_id, const SpiceRect *area, uint8_t *dest,
+			 int dest_stride, int update)
 {
+    RedSurface *surface;
+
+    surface = &worker->surfaces[surface_id];
+
     if (update) {
-        red_update_area(worker, area);
+        red_update_area(worker, area, surface_id);
     }
 
-    worker->draw_funcs.read_pixels(worker->surface.context.canvas, dest, dest_stride, area);
+    worker->draw_funcs.read_pixels(surface->context.canvas, dest, dest_stride, area);
 }
 
 static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
@@ -3620,11 +3710,18 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
     int32_t height;
     uint8_t *dest;
     int dest_stride;
+    uint32_t surface_id;
+    RedSurface *surface;
 
     if (!drawable->qxl_drawable->self_bitmap) {
         return TRUE;
     }
 
+    surface_id = drawable->qxl_drawable->surface_id;
+    validate_surface(worker, surface_id);
+
+    surface = &worker->surfaces[surface_id];
+
     width = drawable->qxl_drawable->bbox.right - drawable->qxl_drawable->bbox.left;
     height = drawable->qxl_drawable->bbox.bottom - drawable->qxl_drawable->bbox.top;
     dest_stride = width * sizeof(uint32_t);
@@ -3639,7 +3736,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
     image->descriptor.flags = 0;
 
     QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique);
-    image->bitmap.flags = QXL_BITMAP_DIRECT | (worker->surface.context.top_down ?
+    image->bitmap.flags = QXL_BITMAP_DIRECT | (surface->context.top_down ?
                                                QXL_BITMAP_TOP_DOWN : 0);
     image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
     image->bitmap.stride = dest_stride;
@@ -3648,7 +3745,8 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
     image->bitmap.data = (QXLPHYSICAL)dest;
     image->bitmap.palette = 0;
 
-    red_get_area(worker, &drawable->qxl_drawable->self_bitmap_area, dest, dest_stride, TRUE);
+    red_get_area(worker, surface_id,
+                 &drawable->qxl_drawable->self_bitmap_area, dest, dest_stride, TRUE);
 
     drawable->self_bitmap = (uint8_t *)image;
     return TRUE;
@@ -3688,6 +3786,7 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, QXLDrawable *qx
     drawable->tree_item.base.id = ++worker->last_id;
 #endif
     ring_item_init(&drawable->list_link);
+    ring_item_init(&drawable->surface_list_link);
 #ifdef UPDATE_AREA_BY_TREE
     ring_item_init(&drawable->collect_link);
 #endif
@@ -3702,15 +3801,71 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, QXLDrawable *qx
     return drawable;
 }
 
+static void surface_flush(RedWorker *worker, int surface_id, SpiceRect *rect)
+{
+    red_update_area(worker, rect, surface_id);
+}
+
+static inline int red_handle_depends_on_target_surface(RedWorker *worker, uint32_t surface_id)
+{
+    RedSurface *surface;
+    RingItem *ring_item;
+
+    surface = &worker->surfaces[surface_id];
+    while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
+        DependItem *depended_item = CONTAINEROF(ring_item, DependItem, ring_item);
+        surface_flush(worker, depended_item->drawable->qxl_drawable->surface_id,
+                      &depended_item->drawable->qxl_drawable->bbox);
+        if (depended_item->drawable) {
+            remove_depended_item(depended_item);
+        }
+    }
+
+    return TRUE;
+}
+
+static inline void add_to_surface_dependency(RedWorker *worker, int depend_on_surface_id,
+                                             DependItem *depend_item, Drawable *drawable)
+{
+    RedSurface *surface;
+
+    if (depend_on_surface_id == -1) {
+        depend_item->drawable = NULL;
+        return;
+    }
+
+    validate_surface(worker, depend_on_surface_id);
+    surface = &worker->surfaces[depend_on_surface_id];
+
+    depend_item->drawable = drawable;
+    surface->refs++;
+    ring_add(&surface->depend_on_me, &depend_item->ring_item);
+}
+
+static inline int red_handle_surfaces_dependencies(RedWorker *worker, Drawable *drawable)
+{
+    int x;
+
+    for (x = 0; x < 3; ++x) {
+        add_to_surface_dependency(worker, drawable->qxl_drawable->surfaces_dest[x],
+                                  &drawable->depend_items[x], drawable);
+    }
+
+    return TRUE;
+}
+
 static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable, uint32_t group_id)
 {
+    int surface_id;
     Drawable *item = get_drawable(worker, drawable->effect, drawable, group_id);
 
     ASSERT(item);
-    PANIC_ON(!worker->surface.context.canvas);
-    ASSERT(worker->surface.refs != 0);
 
-    worker->surface.refs++;
+    surface_id = drawable->surface_id;
+    validate_surface(worker, surface_id);
+
+    ASSERT(worker->surfaces[surface_id].refs != 0);
+    worker->surfaces[surface_id].refs++;
 
     region_add(&item->tree_item.base.rgn, &drawable->bbox);
 #ifdef PIPE_DEBUG
@@ -3745,7 +3900,18 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable
         return;
     }
 
-    if (red_current_add_qxl(worker, item, drawable)) {
+    if (!red_handle_depends_on_target_surface(worker, surface_id)) {
+        release_drawable(worker, item);
+        return;
+    }
+
+    if (!red_handle_surfaces_dependencies(worker, item)) {
+        release_drawable(worker, item);
+        return;
+    }
+
+    if (red_current_add_qxl(worker, &worker->surfaces[surface_id].current, item,
+                            drawable)) {
         worker->drawable_count++;
         if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
             worker->transparent_count++;
@@ -3758,6 +3924,47 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable
     release_drawable(worker, item);
 }
 
+static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
+                                      uint32_t height, int32_t stride, uint8_t depth, void *line_0);
+
+static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface, uint32_t group_id)
+{
+    int surface_id;
+    RedSurface *red_surface;
+    uint8_t *data;
+
+    surface_id = surface->surface_id;
+    __validate_surface(worker, surface_id);
+
+    red_surface = &worker->surfaces[surface_id];
+
+    switch (surface->type) {
+    case QXL_SURFACE_CMD_CREATE: {
+        unsigned long saved_data = (unsigned long)surface->u.surface_create.data;
+        uint32_t height = surface->u.surface_create.height;
+        int32_t stride = surface->u.surface_create.stride;
+        QXLReleaseInfoExt release_info_ext;
+        
+        data = (uint8_t *)get_virt(worker, saved_data, height * abs(stride), group_id);
+        if (stride < 0) {
+            data -= (int32_t)(stride * (height - 1));
+        }
+        red_create_surface(worker, surface_id, surface->u.surface_create.width,
+                           height, stride, surface->u.surface_create.depth, data);
+        release_info_ext.group_id = group_id;
+        release_info_ext.info = &surface->release_info;
+        worker->qxl->release_resource(worker->qxl, release_info_ext);
+        break;
+    }
+    case QXL_SURFACE_CMD_DESTROY:
+        set_surface_release_info(worker, surface_id, &surface->release_info, group_id);
+        red_destroy_surface(worker, surface_id);
+        break;
+    default:
+            red_error("unknown surface command");
+    };
+}
+
 static void localize_path(RedWorker *worker, QXLPHYSICAL *in_path, uint32_t group_id)
 {
     QXLPath *path;
@@ -3973,6 +4180,15 @@ static void image_cache_put(void *opaque, uint64_t id, cairo_surface_t *surface)
     ring_add(&cache->lru, &item->lru_link);
 }
 
+static void *surface_get(void *opaque, uint32_t id)
+{
+    RedWorker *worker = (RedWorker *)opaque;
+
+    validate_surface(worker, id);
+
+    return worker->surfaces[id].context.canvas;
+}
+
 static cairo_surface_t *image_cache_get(void *opaque, uint64_t id)
 {
     ImageCache *cache = (ImageCache *)opaque;
@@ -4113,6 +4329,8 @@ static void localize_bitmap(RedWorker *worker, QXLPHYSICAL *in_bitmap, uint32_t
             local_image->bitmap.palette = (SPICE_ADDRESS)shadow_palette;
         }
         break;
+    case SPICE_IMAGE_TYPE_SURFACE:
+        break;
     default:
         red_error("invalid image type");
     }
@@ -4138,6 +4356,7 @@ static void unlocalize_bitmap(QXLPHYSICAL *bitmap)
     case SPICE_IMAGE_TYPE_QUIC:
     case SPICE_IMAGE_TYPE_FROM_CACHE:
         *bitmap = 0;
+    case SPICE_IMAGE_TYPE_SURFACE:
         break;
     default:
         red_error("invalid image type %u", image->descriptor.type);
@@ -4198,8 +4417,15 @@ static void unlocalize_attr(SpiceLineAttr *attr)
 
 static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
 {
+    uint32_t surface_id;
+    RedSurface *surface;
     SpiceClip clip = drawable->qxl_drawable->clip;
 
+    surface_id = drawable->qxl_drawable->surface_id;
+    validate_surface(worker, surface_id);
+
+    surface = &worker->surfaces[surface_id];
+
     worker->local_images_pos = 0;
     image_cache_eaging(&worker->image_cache);
 
@@ -4211,7 +4437,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
         SpiceFill fill = drawable->qxl_drawable->u.fill;
         localize_brush(worker, &fill.brush, drawable->group_id);
         localize_mask(worker, &fill.mask, drawable->group_id);
-        worker->draw_funcs.draw_fill(worker->surface.context.canvas, &drawable->qxl_drawable->bbox,
+        worker->draw_funcs.draw_fill(surface->context.canvas, &drawable->qxl_drawable->bbox,
                                      &clip, &fill); unlocalize_mask(&fill.mask);
         unlocalize_brush(&fill.brush);
         break;
@@ -4221,7 +4447,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
         localize_brush(worker, &opaque.brush, drawable->group_id);
         localize_bitmap(worker, &opaque.src_bitmap, drawable->group_id);
         localize_mask(worker, &opaque.mask, drawable->group_id);
-        worker->draw_funcs.draw_opaque(worker->surface.context.canvas,
+        worker->draw_funcs.draw_opaque(surface->context.canvas,
                                        &drawable->qxl_drawable->bbox, &clip, &opaque);
         unlocalize_mask(&opaque.mask);
         unlocalize_bitmap(&opaque.src_bitmap);
@@ -4232,7 +4458,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
         SpiceCopy copy = drawable->qxl_drawable->u.copy;
         localize_bitmap(worker, &copy.src_bitmap, drawable->group_id);
         localize_mask(worker, &copy.mask, drawable->group_id);
-        worker->draw_funcs.draw_copy(worker->surface.context.canvas, &drawable->qxl_drawable->bbox,
+        worker->draw_funcs.draw_copy(surface->context.canvas, &drawable->qxl_drawable->bbox,
                                      &clip, &copy);
         unlocalize_mask(&copy.mask);
         unlocalize_bitmap(&copy.src_bitmap);
@@ -4241,7 +4467,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
     case QXL_DRAW_TRANSPARENT: {
         SpiceTransparent transparent = drawable->qxl_drawable->u.transparent;
         localize_bitmap(worker, &transparent.src_bitmap, drawable->group_id);
-        worker->draw_funcs.draw_transparent(worker->surface.context.canvas,
+        worker->draw_funcs.draw_transparent(surface->context.canvas,
                                             &drawable->qxl_drawable->bbox, &clip, &transparent);
         unlocalize_bitmap(&transparent.src_bitmap);
         break;
@@ -4249,13 +4475,13 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
     case QXL_DRAW_ALPHA_BLEND: {
         SpiceAlphaBlnd alpha_blend = drawable->qxl_drawable->u.alpha_blend;
         localize_bitmap(worker, &alpha_blend.src_bitmap, drawable->group_id);
-        worker->draw_funcs.draw_alpha_blend(worker->surface.context.canvas,
+        worker->draw_funcs.draw_alpha_blend(surface->context.canvas,
                                             &drawable->qxl_drawable->bbox, &clip, &alpha_blend);
         unlocalize_bitmap(&alpha_blend.src_bitmap);
         break;
     }
     case QXL_COPY_BITS: {
-        worker->draw_funcs.copy_bits(worker->surface.context.canvas, &drawable->qxl_drawable->bbox,
+        worker->draw_funcs.copy_bits(surface->context.canvas, &drawable->qxl_drawable->bbox,
                                      &clip, &drawable->qxl_drawable->u.copy_bits.src_pos);
         break;
     }
@@ -4263,7 +4489,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
         SpiceBlend blend = drawable->qxl_drawable->u.blend;
         localize_bitmap(worker, &blend.src_bitmap, drawable->group_id);
         localize_mask(worker, &blend.mask, drawable->group_id);
-        worker->draw_funcs.draw_blend(worker->surface.context.canvas, &drawable->qxl_drawable->bbox,
+        worker->draw_funcs.draw_blend(surface->context.canvas, &drawable->qxl_drawable->bbox,
                                       &clip, &blend);
         unlocalize_mask(&blend.mask);
         unlocalize_bitmap(&blend.src_bitmap);
@@ -4272,7 +4498,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
     case QXL_DRAW_BLACKNESS: {
         SpiceBlackness blackness = drawable->qxl_drawable->u.blackness;
         localize_mask(worker, &blackness.mask, drawable->group_id);
-        worker->draw_funcs.draw_blackness(worker->surface.context.canvas,
+        worker->draw_funcs.draw_blackness(surface->context.canvas,
                                           &drawable->qxl_drawable->bbox, &clip, &blackness);
         unlocalize_mask(&blackness.mask);
         break;
@@ -4280,7 +4506,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
     case QXL_DRAW_WHITENESS: {
         SpiceWhiteness whiteness = drawable->qxl_drawable->u.whiteness;
         localize_mask(worker, &whiteness.mask, drawable->group_id);
-        worker->draw_funcs.draw_whiteness(worker->surface.context.canvas,
+        worker->draw_funcs.draw_whiteness(surface->context.canvas,
                                           &drawable->qxl_drawable->bbox, &clip, &whiteness);
         unlocalize_mask(&whiteness.mask);
         break;
@@ -4288,7 +4514,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
     case QXL_DRAW_INVERS: {
         SpiceInvers invers = drawable->qxl_drawable->u.invers;
         localize_mask(worker, &invers.mask, drawable->group_id);
-        worker->draw_funcs.draw_invers(worker->surface.context.canvas,
+        worker->draw_funcs.draw_invers(surface->context.canvas,
                                        &drawable->qxl_drawable->bbox, &clip, &invers);
         unlocalize_mask(&invers.mask);
         break;
@@ -4298,7 +4524,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
         localize_brush(worker, &rop3.brush, drawable->group_id);
         localize_bitmap(worker, &rop3.src_bitmap, drawable->group_id);
         localize_mask(worker, &rop3.mask, drawable->group_id);
-        worker->draw_funcs.draw_rop3(worker->surface.context.canvas, &drawable->qxl_drawable->bbox,
+        worker->draw_funcs.draw_rop3(surface->context.canvas, &drawable->qxl_drawable->bbox,
                                      &clip, &rop3); unlocalize_mask(&rop3.mask);
         unlocalize_bitmap(&rop3.src_bitmap);
         unlocalize_brush(&rop3.brush);
@@ -4309,7 +4535,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
         localize_brush(worker, &stroke.brush, drawable->group_id);
         localize_path(worker, &stroke.path, drawable->group_id);
         localize_attr(worker, &stroke.attr, drawable->group_id);
-        worker->draw_funcs.draw_stroke(worker->surface.context.canvas,
+        worker->draw_funcs.draw_stroke(surface->context.canvas,
                                        &drawable->qxl_drawable->bbox, &clip, &stroke);
         unlocalize_attr(&stroke.attr);
         unlocalize_path(&stroke.path);
@@ -4321,7 +4547,7 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
         localize_brush(worker, &text.fore_brush, drawable->group_id);
         localize_brush(worker, &text.back_brush, drawable->group_id);
         localize_str(worker, &text.str, drawable->group_id);
-        worker->draw_funcs.draw_text(worker->surface.context.canvas, &drawable->qxl_drawable->bbox,
+        worker->draw_funcs.draw_text(surface->context.canvas, &drawable->qxl_drawable->bbox,
                                      &clip, &text);
         unlocalize_str(&text.str);
         unlocalize_brush(&text.back_brush);
@@ -4336,17 +4562,40 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable)
 
 #ifndef DRAW_ALL
 
+static void red_handle_drawable_depend_on_surface(RedWorker *worker, Drawable *drawable)
+{
+    int x;
+
+    for(x = 0; x < 3; ++x) {
+        if (drawable->depend_items[x].drawable) {
+            Drawable *_drawable;
+
+            ASSERT(ring_item_is_linked(&drawable->depend_items[x].ring_item));
+            _drawable = drawable->depend_items[x].drawable;
+            remove_depended_item(&drawable->depend_items[x]);
+            //surface_flush(worker, _drawable->qxl_drawable->surface_id,
+            //              &_drawable->qxl_drawable->bbox); ?
+        }
+    }
+}
+
 static void red_draw_drawable(RedWorker *worker, Drawable *drawable)
 {
 #ifdef UPDATE_AREA_BY_TREE
+    uint32_t surface_id;
+    RedSurface *surface;
+
+    surface_id = &worker->surfaces[surface_id];
+    validate_surface(worker, surface_id);
     //todo: add need top mask flag
-    worker->draw_funcs.set_top_mask(worker->surface.context.canvas,
+    worker->draw_funcs.set_top_mask(surface->context.canvas,
                                     drawable->tree_item.base.rgn.num_rects,
                                     drawable->tree_item.base.rgn.rects);
 #endif
+    red_handle_drawable_depend_on_surface(worker, drawable);
     red_draw_qxl_drawable(worker, drawable);
 #ifdef UPDATE_AREA_BY_TREE
-    worker->draw_funcs.clear_top_mask(worker->surface.context.canvas);
+    worker->draw_funcs.clear_top_mask(surface->context.canvas);
 #endif
 }
 
@@ -4399,15 +4648,20 @@ static inline void __red_collect_for_update(RedWorker *worker, Ring *ring, RingI
     }
 }
 
-static void red_update_area(RedWorker *worker, const SpiceRect *area)
+static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id)
 {
-    Ring *ring = &worker->current;
+    RedSurface *surface;
+    Ring *ring;
     RingItem *ring_item;
     Ring items;
     QRegion rgn;
 
+    validate_surface(worker, surface_id);
+    surface = &worker->surfaces[surface_id];
+    ring = &surface->current;
+
     if (!(ring_item = ring_get_head(ring))) {
-        worker->draw_context.validate_area(worker->draw_context.canvas,
+        worker->draw_context.validate_area(surface->context.canvas,
                                            &worker->dev_info.surface0_area, area);
         return;
     }
@@ -4428,24 +4682,30 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area)
         current_remove_drawable(worker, drawable);
         container_cleanup(worker, container);
     }
-    worker->draw_funcs.validate_area(worker->surface.context.canvas, worker->surface.context.stride,
-                                     worker->surface.context.line_0, area);
+    worker->draw_funcs.validate_area(surface->context.canvas, surface->context.stride,
+                                     surface->context.line_0, area);
 }
 
 #else
 
-static void red_update_area(RedWorker *worker, const SpiceRect *area)
+static void red_update_area(RedWorker *worker, const SpiceRect *area, uint32_t surface_id)
 {
-    Ring *ring = &worker->current_list;
-    RingItem *ring_item = ring;
+    RedSurface *surface;
+    Ring *ring;
+    RingItem *ring_item;
     QRegion rgn;
     Drawable *last = NULL;
     Drawable *now;
 
+    validate_surface(worker, surface_id);
+    surface = &worker->surfaces[surface_id];
+    ring = &surface->current_list;
+    ring_item = ring;
+
     region_init(&rgn);
     region_add(&rgn, area);
     while ((ring_item = ring_next(ring, ring_item))) {
-        now = CONTAINEROF(ring_item, Drawable, list_link);
+        now = CONTAINEROF(ring_item, Drawable, surface_list_link);
         if (region_intersects(&rgn, &now->tree_item.base.rgn)) {
             last = now;
             break;
@@ -4454,24 +4714,25 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area)
     region_destroy(&rgn);
 
     if (!last) {
-        worker->draw_funcs.validate_area(worker->surface.context.canvas,
-                                         worker->surface.context.stride,
-                                         worker->surface.context.line_0, area);
+        worker->draw_funcs.validate_area(surface->context.canvas,
+                                         surface->context.stride,
+                                         surface->context.line_0, area);
         return;
     }
 
     do {
         Container *container;
 
-        ring_item = ring_get_tail(&worker->current_list);
-        now = CONTAINEROF(ring_item, Drawable, list_link);
+        ring_item = ring_get_tail(ring);
+        now = CONTAINEROF(ring_item, Drawable, surface_list_link);
         red_draw_drawable(worker, now);
         container = now->tree_item.base.container;
         current_remove_drawable(worker, now);
         container_cleanup(worker, container);
     } while (now != last);
-    worker->draw_funcs.validate_area(worker->surface.context.canvas, worker->surface.context.stride,
-                                     worker->surface.context.line_0, area);
+    worker->draw_funcs.validate_area(surface->context.canvas, surface->context.stride,
+                                     surface->context.line_0, area);
+
 }
 
 #endif
@@ -4664,7 +4925,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size)
             QXLUpdateCmd *draw_cmd = (QXLUpdateCmd *)get_virt(worker, ext_cmd.cmd.data,
                                                               sizeof(QXLUpdateCmd),
                                                               ext_cmd.group_id);
-            red_update_area(worker, &draw_cmd->area);
+            red_update_area(worker, &draw_cmd->area, draw_cmd->surface_id);
             worker->qxl->notify_update(worker->qxl, draw_cmd->update_id);
             release_info_ext.group_id = ext_cmd.group_id;
             release_info_ext.info = &draw_cmd->release_info;
@@ -4681,6 +4942,12 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size)
             worker->qxl->release_resource(worker->qxl, release_info_ext);
             break;
         }
+        case QXL_CMD_SURFACE: {
+            QXLSurfaceCmd *surface = (QXLSurfaceCmd *)get_virt(worker, ext_cmd.cmd.data,
+                                                               sizeof(QXLSurfaceCmd), ext_cmd.group_id);
+            red_process_surface(worker, surface, ext_cmd.group_id);
+            break;
+        }
         default:
             red_error("bad command type");
         }
@@ -4730,13 +4997,13 @@ static void red_add_screen_image(RedWorker *worker)
     int stride;
     SpiceRect area;
 
-    if (!worker->display_channel || !worker->surface.context.canvas) {
+    if (!worker->display_channel || !worker->surfaces[0].context.canvas) {
         return;
     }
 
-    stride = worker->surface.context.width << 2;
+    stride = worker->surfaces[0].context.width << 2;
     if (!(item = (ImageItem *)malloc(sizeof(ImageItem) +
-                                     worker->surface.context.height * stride))) {
+                                     worker->surfaces[0].context.height * stride))) {
         //warn
         return;
     }
@@ -4745,15 +5012,15 @@ static void red_add_screen_image(RedWorker *worker)
 
     item->refs = 1;
     item->pos.x = item->pos.y = 0;
-    item->width = worker->surface.context.width;
-    item->height = worker->surface.context.height;
+    item->width = worker->surfaces[0].context.width;
+    item->height = worker->surfaces[0].context.height;
     item->stride = stride;
-    item->top_down = worker->surface.context.top_down;
+    item->top_down = worker->surfaces[0].context.top_down;
 
     area.top = area.left = 0;
-    area.right = worker->surface.context.width;
-    area.bottom = worker->surface.context.height;
-    worker->draw_funcs.read_pixels(worker->surface.context.canvas, item->data, stride, &area);
+    area.right = worker->surfaces[0].context.width;
+    area.bottom = worker->surfaces[0].context.height;
+    worker->draw_funcs.read_pixels(worker->surfaces[0].context.canvas, item->data, stride, &area);
     red_pipe_add_image_item(worker, item);
     release_image_item(item);
     display_channel_push(worker);
@@ -6062,6 +6329,62 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D
     }
 
     switch (qxl_image->descriptor.type) {
+    //right now send bitmap to the client - change in next commits
+    //alot of duplicated code, but going to throw it anyway
+    case SPICE_IMAGE_TYPE_SURFACE: {
+        int surface_id;
+        int i;
+        uint32_t y;
+        uint32_t stride;
+        RedSurface *surface;
+        SpiceRect area;
+
+        surface_id = qxl_image->surface_image.surface_id;
+        validate_surface(worker, surface_id);
+
+        surface = &worker->surfaces[surface_id];
+
+        image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
+        image->descriptor.flags = 0;
+        image->descriptor.width = surface->context.width;
+        image->descriptor.height = surface->context.height;
+
+        image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
+        image->bitmap.flags = QXL_BITMAP_DIRECT;
+        image->bitmap.flags |= !surface->context.top_down ? QXL_BITMAP_TOP_DOWN : 0;
+        image->bitmap.x = surface->context.width;
+        image->bitmap.y = surface->context.height;
+        image->bitmap.stride = abs(surface->context.stride); //surface->context.width << 2;
+        image->bitmap.palette = 0;
+        image->bitmap.data = (SPICE_ADDRESS)surface->context.line_0;
+        if (surface->context.stride < 0) {
+            image->bitmap.data += (int32_t)(surface->context.stride * (surface->context.height - 1));
+            printf("nic %lu and %u\n", image->bitmap.data, image->bitmap.y * image->bitmap.stride);
+            //memset ((void *)image->bitmap.data, 100, image->bitmap.y * image->bitmap.stride);
+        }
+
+        area.top = area.left = 0;
+        area.right = surface->context.width;
+        area.bottom = surface->context.height;
+
+        red_update_area(worker, &area, surface_id);
+        for (i = 0; i < 3; ++i) {
+            if (drawable->depend_items[i].drawable) {
+                remove_depended_item(&drawable->depend_items[i]);
+            }
+        }
+
+        y = image->bitmap.y;
+        stride = image->bitmap.stride;
+        image->bitmap.flags = image->bitmap.flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
+
+        add_buf(channel, BUF_TYPE_RAW, image, sizeof(SpiceBitmapImage), 0, 0);
+        data = (uint8_t *)image->bitmap.data;
+	image->bitmap.data = channel->send_data.header.size;
+        add_buf(channel, BUF_TYPE_RAW, data, y * stride, 0, 0);
+  
+        break;
+    }
     case SPICE_IMAGE_TYPE_BITMAP:
 #ifdef DUMP_BITMAP
         dump_bitmap(display_channel->base.worker, &qxl_image->bitmap, drawable->group_id);
@@ -6223,6 +6546,9 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
 {
     QXLDrawable *drawable = item->qxl_drawable;
 
+    //hack to be removed
+    PANIC_ON(drawable->surface_id != 0);
+
     RedChannel *channel = &display_channel->base;
     switch (drawable->type) {
     case QXL_DRAW_FILL:
@@ -7438,11 +7764,18 @@ static void __show_tree_call(TreeItem *item, void *data)
 
 void red_show_tree(RedWorker *worker)
 {
+    int x;
+
     ShowTreeData show_tree_data;
     show_tree_data.worker = worker;
     show_tree_data.level = 0;
     show_tree_data.container = NULL;
-    current_tree_for_each(worker, __show_tree_call, &show_tree_data);
+    for (x = 0; x < NUM_SURFACES; ++x) {
+        if (worker->surfaces[x].context.canvas) {
+            current_tree_for_each(worker, &worker->surfaces[x].current, __show_tree_call,
+                                  &show_tree_data);
+        }
+    }
 }
 
 static inline int channel_is_connected(RedChannel *channel)
@@ -7560,9 +7893,9 @@ static CairoCanvas *create_cairo_context(RedWorker *worker, uint32_t width, uint
                   cairo_status_to_string(cairo_status(cairo)));
     }
 
-    return canvas_create(cairo, depth, &worker->image_cache, image_cache_put, image_cache_get,
-                         worker, cb_get_virt_preload_group, worker,
-                         cb_validate_virt_preload_group);
+    return canvas_create(cairo, depth, worker, surface_get, &worker->image_cache,
+                         image_cache_put, image_cache_get,worker, cb_get_virt_preload_group,
+                         worker, cb_validate_virt_preload_group);
 }
 
 static void destroy_gl_canvas(GLCanvas *canvas)
@@ -7622,7 +7955,8 @@ static GLCanvas *create_ogl_context_common(RedWorker *worker, OGLCtx *ctx, uint3
     GLCanvas *canvas;
 
     oglctx_make_current(ctx);
-    if (!(canvas = gl_canvas_create(ctx, width, height, depth, &worker->image_cache,
+    if (!(canvas = gl_canvas_create(ctx, worker, surface_get,
+                                    width, height, depth, &worker->image_cache,
                                     image_cache_put, image_cache_get, worker,
                                     cb_get_virt_preload_group,
                                     worker, cb_validate_virt_preload_group))) {
@@ -7752,19 +8086,23 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uin
                                       uint32_t height, int32_t stride, uint8_t depth, void *line_0)
 {
     uint32_t i;
-    RedSurface *surface = &worker->surface;
-
+    RedSurface *surface = &worker->surfaces[surface_id];
+ printf("blalalala %d\n", surface_id);
     if (stride >= 0) {
         PANIC("Untested path stride >= 0");
     }
     PANIC_ON(surface->context.canvas);
-    ASSERT(surface_id == 0);
 
     surface->context.width = width;
     surface->context.height = height;
     surface->context.depth = depth;
     surface->context.stride = stride;
     surface->context.line_0 = line_0;
+    memset(line_0 + (int32_t)(stride * (height - 1)), 0, height*abs(stride));
+    surface->release_info = NULL;
+    ring_init(&surface->current);
+    ring_init(&surface->current_list);
+    ring_init(&surface->depend_on_me);
     surface->refs = 1;
 
     if (worker->renderer != RED_RENDERER_INVALID) {
@@ -7774,7 +8112,9 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uin
         if (!surface->context.canvas) {
             PANIC("drawing canvas creating failed - can`t create same type canvas");
         }
-        red_create_surface_item(worker, surface);
+        if (surface_id == 0) { //fix me
+            red_create_surface_item(worker, surface);
+        }
         return;
     }
 
@@ -7782,7 +8122,7 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uin
         surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderers[i],
                                                             width, height, stride,
                                                             surface->context.depth, line_0);
-        if (surface->context.canvas) {
+        if (surface->context.canvas && surface_id == 0) { //fixme
             worker->renderer = worker->renderers[i];
             surface_init_draw_funcs(worker, worker->renderers[i]);
             red_create_surface_item(worker, surface);
@@ -7845,7 +8185,7 @@ static void push_new_primary_surface(RedWorker *worker)
     if ((display_channel = worker->display_channel)) {
         red_pipe_add_type(&display_channel->base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
         if (!display_channel->base.migrate) {
-            red_create_surface_item(worker, &worker->surface);
+            red_create_surface_item(worker, &worker->surfaces[0]);
         }
         display_channel_push(worker);
     }
@@ -7896,7 +8236,7 @@ static void on_new_display_channel(RedWorker *worker)
         return;
     }
     display_channel->base.messages_window = 0;
-    if (worker->surface.context.canvas) {
+    if (worker->surfaces[0].context.canvas) {
         red_current_flush(worker);
         push_new_primary_surface(worker);
         red_add_screen_image(worker);
@@ -8514,7 +8854,7 @@ static void on_new_cursor_channel(RedWorker *worker)
 
     channel->base.messages_window = 0;
     red_pipe_add_type(&channel->base, PIPE_ITEM_TYPE_SET_ACK);
-    if (worker->surface.context.canvas && !channel->base.migrate) {
+    if (worker->surfaces[0].context.canvas && !channel->base.migrate) {
         red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
 }
@@ -8710,12 +9050,15 @@ static void red_wait_outgoiong_item(RedChannel *channel)
 static inline void handle_dev_update(RedWorker *worker)
 {
     RedWorkeMessage message;
+    const SpiceRect *rect;
+    uint32_t *surface_id;
 
-    ASSERT(worker->surface.context.canvas && worker->running);
+    ASSERT(worker->surfaces[0].context.canvas && worker->running);
 
     flush_display_commands(worker);
 
-    red_update_area(worker, worker->qxl->get_update_area(worker->qxl));
+    worker->qxl->get_update_area(worker->qxl, &rect, &surface_id);
+    red_update_area(worker, rect, *surface_id);
     message = RED_WORKER_MESSAGE_READY;
     write_message(worker->channel, &message);
 }
@@ -8776,7 +9119,7 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
 
     ASSERT(surface_id == 0);
 
-    if (worker->surface.context.canvas) {
+    if (worker->surfaces[0].context.canvas) {
         destroy_surface_wait(worker);
     }
 
@@ -8786,10 +9129,17 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
 
 static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 {
+    int i;
     RedWorkeMessage message;
 
     destroy_surface_wait(worker);
-    __red_destroy_surface(worker);
+
+    //to handle better
+    for (i = 0; i < NUM_SURFACES; ++i) {
+        if (worker->surfaces[i].context.canvas) {
+            __red_destroy_surface(worker, i);
+        }
+    }
     ASSERT(ring_is_empty(&worker->streams));
 
     red_wait_outgoiong_item((RedChannel *)worker->cursor_channel);
@@ -8809,7 +9159,10 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
         }
     }
 
-    ASSERT(!worker->surface.context.canvas);
+    //to handle better
+    for (i = 0; i < NUM_SURFACES; ++i) {
+        ASSERT(!worker->surfaces[i].context.canvas);
+    }
 
     worker->cursor_visible = TRUE;
     worker->cursor_position.x = worker->cursor_position.y = 0;
@@ -8844,7 +9197,7 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
                        line_0);
 
     if (worker->display_channel) {
-        red_create_surface_item(worker, &worker->surface);
+        red_create_surface_item(worker, &worker->surfaces[0]);
         red_pipe_add_verb(&worker->display_channel->base, SPICE_MSG_DISPLAY_MARK);
         display_channel_push(worker);
     }
@@ -8882,10 +9235,10 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
 
 
     destroy_surface_wait(worker);
-    red_destroy_surface(worker);
+    red_destroy_surface(worker, 0);
     ASSERT(ring_is_empty(&worker->streams));
 
-    ASSERT(!worker->surface.context.canvas);
+    ASSERT(!worker->surfaces[surface_id].context.canvas);
 
     worker->cursor_visible = TRUE;
     worker->cursor_position.x = worker->cursor_position.y = 0;
@@ -9154,7 +9507,6 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
     worker->image_compression = init_data->image_compression;
     worker->streaming_video = init_data->streaming_video;
     ring_init(&worker->current_list);
-    ring_init(&worker->current);
     image_cache_init(&worker->image_cache);
     drawables_init(worker);
     cursor_items_init(worker);
@@ -9186,6 +9538,8 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
     worker->generation_bits = init_data->memslot_gen_bits;
     worker->mem_slot_bits = init_data->memslot_id_bits;
     worker->internal_groupslot_id = init_data->internal_groupslot_id;
+    PANIC_ON(init_data->n_surfaces > NUM_SURFACES);
+    worker->n_surfaces = init_data->n_surfaces;
     red_create_mem_slots(worker);
 
     message = RED_WORKER_MESSAGE_READY;
diff --git a/server/red_worker.h b/server/red_worker.h
index 765b7d8..1834265 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -96,6 +96,7 @@ typedef struct WorkerInitData {
     uint8_t memslot_gen_bits;
     uint8_t memslot_id_bits;
     uint8_t internal_groupslot_id;
+    uint32_t n_surfaces;
 } WorkerInitData;
 
 void *red_worker_main(void *arg);
diff --git a/server/vd_interface.h b/server/vd_interface.h
index 674fae0..6d76b9e 100644
--- a/server/vd_interface.h
+++ b/server/vd_interface.h
@@ -153,6 +153,7 @@ typedef struct QXLDevInitInfo {
     uint8_t memslot_id_bits;
     uint32_t qxl_ram_size;
     uint8_t internal_groupslot_id;
+    uint32_t n_surfaces;
 } QXLDevInitInfo;
 
 struct QXLDevMemSlot {
@@ -178,6 +179,8 @@ struct QXLDevSurfaceCreate {
     uint32_t group_id;
 };
 
+struct SpiceRect;
+
 struct QXLInterface {
     VDInterface base;
 
@@ -196,7 +199,7 @@ struct QXLInterface {
     void (*release_resource)(QXLInterface *qxl, struct QXLReleaseInfoExt release_info);




diff --git a/spice/draw.h b/spice/draw.h
index 254e0b0..075324b 100644
--- a/spice/draw.h
+++ b/spice/draw.h
@@ -155,6 +155,7 @@ enum {
     SPICE_IMAGE_TYPE_LZ_RGB,
     SPICE_IMAGE_TYPE_GLZ_RGB,
     SPICE_IMAGE_TYPE_FROM_CACHE,
+    SPICE_IMAGE_TYPE_SURFACE,
 };
 
 enum {
@@ -203,6 +204,15 @@ typedef struct SPICE_ATTR_PACKED SpiceBitmapImage {
     SpiceBitmap bitmap;
 } SpiceBitmapImage;
 
+typedef struct SPICE_ATTR_PACKED SpiceSurface {
+    uint32_t surface_id;
+} SpiceSurface;
+
+typedef struct SPICE_ATTR_PACKED SpiceSurfaceImage {
+    SpiceImageDescriptor descriptor; //?
+    SpiceSurface surface;
+} SpiceSurfaceImage;
+
 typedef struct SPICE_ATTR_PACKED SpiceQUICData {
     uint32_t data_size;
     uint8_t data[0];
diff --git a/spice/qxl_dev.h b/spice/qxl_dev.h
index 353018d..01b6f1a 100644
--- a/spice/qxl_dev.h
+++ b/spice/qxl_dev.h
@@ -91,6 +91,7 @@ typedef struct SPICE_ATTR_PACKED QXLRom {
     uint8_t slot_gen_bits;
     uint8_t slot_id_bits;
     uint8_t slot_generation;
+    uint32_t n_surfaces;
 } QXLRom;
 
 typedef struct SPICE_ATTR_PACKED QXLMode {
@@ -118,6 +119,7 @@ enum QXLCmdType {
     QXL_CMD_UPDATE,
     QXL_CMD_CURSOR,
     QXL_CMD_MESSAGE,
+    QXL_CMD_SURFACE,
 };
 
 typedef struct SPICE_ATTR_PACKED QXLCommand {
@@ -169,6 +171,7 @@ typedef struct SPICE_ATTR_PACKED QXLRam {
     QXLCursorRing cursor_ring;
     QXLReleaseRing release_ring;
     SpiceRect update_area;
+    uint32_t update_surface;
     QXLMemSlot mem_slot;
     QXLSurfaceCreate create_surface;
     uint64_t flags;
@@ -200,6 +203,7 @@ typedef struct SPICE_ATTR_PACKED QXLUpdateCmd {
     QXLReleaseInfo release_info;
     SpiceRect area;
     uint32_t update_id;
+    uint32_t surface_id;
 } QXLUpdateCmd;
 
 typedef struct SPICE_ATTR_PACKED QXLCursor {
@@ -274,6 +278,7 @@ typedef struct SPICE_ATTR_PACKED QXLCopyBits {
 
 typedef struct SPICE_ATTR_PACKED QXLDrawable {
     QXLReleaseInfo release_info;
+    uint32_t surface_id;
     uint8_t effect;
     uint8_t type;
     uint8_t self_bitmap;
@@ -281,6 +286,8 @@ typedef struct SPICE_ATTR_PACKED QXLDrawable {
     SpiceRect bbox;
     SpiceClip clip;
     uint32_t mm_time;
+    int32_t surfaces_dest[3];
+    SpiceRect surfaces_rects[3];
     union {
         SpiceFill fill;
         SpiceOpaque opaque;
@@ -298,6 +305,29 @@ typedef struct SPICE_ATTR_PACKED QXLDrawable {
     } u;
 } QXLDrawable;
 
+enum QXLSurfaceCmdType {
+    QXL_SURFACE_CMD_CREATE,
+    QXL_SURFACE_CMD_DESTROY,
+};
+
+typedef struct SPICE_ATTR_PACKED QXLSurface {
+    uint8_t depth;
+    uint32_t width;
+    uint32_t height;
+    int32_t stride;
+    QXLPHYSICAL data;
+} QXLSurface;
+
+typedef struct SPICE_ATTR_PACKED QXLSurfaceCmd {
+    QXLReleaseInfo release_info;
+    uint32_t surface_id;
+    uint8_t type;
+    uint32_t flags;
+    union {
+        QXLSurface surface_create;
+    } u;
+} QXLSurfaceCmd;
+
 typedef struct SPICE_ATTR_PACKED QXLClipRects {
     uint32_t num_rects;
     QXLDataChunk chunk;
@@ -349,6 +379,7 @@ typedef struct SPICE_ATTR_PACKED QXLImage {
     union { // variable length
         SpiceBitmap bitmap;
         SpiceQUICData quic;
+        SpiceSurface surface_image;
     };
 } QXLImage;
 



More information about the Spice-devel mailing list