Index: /trunk/include/VBox/HostServices/VBoxCrOpenGLSvc.h
===================================================================
--- /trunk/include/VBox/HostServices/VBoxCrOpenGLSvc.h	(revision 50753)
+++ /trunk/include/VBox/HostServices/VBoxCrOpenGLSvc.h	(revision 50754)
@@ -33,4 +33,5 @@
 #include <VBox/hgcmsvc.h>
 #include <VBox/VBoxVideo.h>
+#include <VBox/VBoxVideoHost3D.h>
 
 /* crOpenGL host functions */
@@ -45,9 +46,9 @@
 #define SHCRGL_HOST_FN_VIEWPORT_CHANGED (15)
 #define SHCRGL_HOST_FN_SET_OUTPUT_REDIRECT (20)
-#define SHCRGL_HOST_FN_CRCMD_NOTIFY_CMDS   (21)
 #define SHCRGL_HOST_FN_DEV_RESIZE          (22)
 #define SHCRGL_HOST_FN_VIEWPORT_CHANGED2 (23)
 #define SHCRGL_HOST_FN_TAKE_SCREENSHOT (24)
 #define SHCRGL_HOST_FN_WINDOWS_SHOW (25)
+#define SHCRGL_HOST_FN_CTL          (26)
 /* crOpenGL guest functions */
 #define SHCRGL_GUEST_FN_WRITE       (2)
Index: /trunk/include/VBox/VBoxVideo.h
===================================================================
--- /trunk/include/VBox/VBoxVideo.h	(revision 50753)
+++ /trunk/include/VBox/VBoxVideo.h	(revision 50754)
@@ -853,8 +853,7 @@
 #define VBVA_SCANLINE_CFG    13 /* configures scanline, see VBVASCANLINECFG below */
 #define VBVA_SCANLINE_INFO   14 /* requests scanline info, see VBVASCANLINEINFO below */
-#define VBVA_CMDVBVA_ENABLE  15 /* enables command ring buffer VBVA */
 #define VBVA_CMDVBVA_SUBMIT  16 /* inform host about VBVA Command submission */
 #define VBVA_CMDVBVA_FLUSH   17 /* inform host about VBVA Command submission */
-#define VBVA_VBVACMD_CTL     18
+#define VBVA_CMDVBVA_CTL     18 /* G->H DMA command             */
 
 /* host->guest commands */
@@ -1450,16 +1449,4 @@
 } VBOXVDMACMD_CHROMIUM_CTL, *PVBOXVDMACMD_CHROMIUM_CTL;
 
-typedef struct VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP
-{
-    VBOXVDMACMD_CHROMIUM_CTL Hdr;
-    union
-    {
-        void *pvVRamBase;
-        uint64_t uAlignment;
-    };
-    uint64_t cbVRam;
-    struct VBOXCRCMD_CLTINFO *pCrCmdClientInfo;
-} VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP, *PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP;
-
 
 typedef struct PDMIDISPLAYVBVACALLBACKS *HCRHGSMICMDCOMPLETION;
@@ -1747,4 +1734,19 @@
 } VBOXCMDVBVA_PAGING_FILL;
 
+#define VBOXCMDVBVACTL_TYPE_ENABLE     1
+#define VBOXCMDVBVACTL_TYPE_3DCTL      2
+
+typedef struct VBOXCMDVBVA_CTL
+{
+    uint32_t u32Type;
+    int32_t i32Result;
+} VBOXCMDVBVA_CTL;
+
+typedef struct VBOXCMDVBVA_CTL_ENABLE
+{
+    VBOXCMDVBVA_CTL Hdr;
+    VBVAENABLE Enable;
+} VBOXCMDVBVA_CTL_ENABLE;
+
 # pragma pack()
 
Index: /trunk/include/VBox/VBoxVideo3D.h
===================================================================
--- /trunk/include/VBox/VBoxVideo3D.h	(revision 50753)
+++ /trunk/include/VBox/VBoxVideo3D.h	(revision 50754)
@@ -142,35 +142,3 @@
 
 
-/* interface between the VGA device and 3D Server Backend
- * VGA device and 3D backend work together in processing the VBVA-based ring buffer commands comming from guest.
- * With this interaction VGA device acts like a client, while 3D backend acts as a server.
- * VGA device can process some commands itself, while some of them are delegated to the 3D backend.
- *
- * */
-/* client handle, passed to client callbacks (see below) */
-typedef struct VBOXVDMAHOST *HVBOXCRCMDCLT;
-
-
-typedef struct VBOXCMDVBVA_HDR *PVBOXCMDVBVA_HDR;
-
-/* server queries client for the next command,
- * the obtained command must be returned to the client right after it gets processed,
- * the next PFNVBOXCRCMD_CLT_CMDGET call completes the previously submitted command,
- * Must not be called from the EMT thread.*/
-typedef DECLCALLBACKPTR(int, PFNVBOXCRCMD_CLT_CMDGET)(HVBOXCRCMDCLT hClt, PVBOXCMDVBVA_HDR *ppNextCmd, uint32_t *pcbNextCmd);
-
-struct VBVAINFOSCREEN;
-/* server queries for display mode.*/
-typedef DECLCALLBACKPTR(int, PFNVBOXCRCMD_CLT_DMGET)(HVBOXCRCMDCLT hClt, uint32_t idScreen, struct VBVAINFOSCREEN *pScreen, void **ppvVram);
-
-/* Client callbacks (i.e. those client exposes to the server) */
-typedef struct VBOXCRCMD_CLTINFO
-{
-    HVBOXCRCMDCLT hClient;
-    PFNVBOXCRCMD_CLT_CMDGET pfnCmdGet;
-    PFNVBOXCRCMD_CLT_DMGET pfnDmGet;
-} VBOXCRCMD_CLTINFO;
-
-
-
 #endif /* #ifndef ___VBox_VBoxVideo3D_h */
Index: /trunk/include/VBox/vmm/pdmifs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmifs.h	(revision 50753)
+++ /trunk/include/VBox/vmm/pdmifs.h	(revision 50754)
@@ -633,4 +633,6 @@
 /** Pointer to a display connector interface. */
 typedef struct PDMIDISPLAYCONNECTOR *PPDMIDISPLAYCONNECTOR;
+struct VBOXCRCMDCTL;
+typedef DECLCALLBACKPTR(void, PFNCRCTLCOMPLETION)(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion);
 /**
  * Display connector interface (up).
@@ -750,8 +752,8 @@
      * @thread  The emulation thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnCrCmdNotifyCmds, (PPDMIDISPLAYCONNECTOR pInterface));
-
-    /**
-     * Process the guest chromium command.
+    DECLR3CALLBACKMEMBER(void, pfnCrHgsmiCommandProcess, (PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd));
+
+    /**
+     * Process the guest chromium control command.
      *
      * @param   pInterface          Pointer to this interface.
@@ -759,5 +761,5 @@
      * @thread  The emulation thread.
      */
-    DECLR3CALLBACKMEMBER(void, pfnCrHgsmiCommandProcess, (PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd));
+    DECLR3CALLBACKMEMBER(void, pfnCrHgsmiControlProcess, (PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl));
 
     /**
@@ -768,5 +770,8 @@
      * @thread  The emulation thread.
      */
-    DECLR3CALLBACKMEMBER(void, pfnCrHgsmiControlProcess, (PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl));
+    DECLR3CALLBACKMEMBER(int, pfnCrHgcmCtlSubmit, (PPDMIDISPLAYCONNECTOR pInterface,
+                                            struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
+                                            PFNCRCTLCOMPLETION pfnCompletion,
+                                            void *pvCompletion));
 
     /**
@@ -3066,4 +3071,9 @@
     DECLR3CALLBACKMEMBER(int, pfnCrHgsmiControlCompleteAsync, (PPDMIDISPLAYVBVACALLBACKS pInterface,
                                                                PVBOXVDMACMD_CHROMIUM_CTL pCmd, int rc));
+
+    DECLR3CALLBACKMEMBER(int, pfnCrCtlSubmit, (PPDMIDISPLAYVBVACALLBACKS pInterface,
+                                                                   struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
+                                                                   PFNCRCTLCOMPLETION pfnCompletion,
+                                                                   void *pvCompletion));
 } PDMIDISPLAYVBVACALLBACKS;
 /** PDMIDISPLAYVBVACALLBACKS  */
Index: /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp	(revision 50753)
+++ /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp	(revision 50754)
@@ -114,46 +114,123 @@
 }
 
-static bool vboxVBVAExInformHost(PVBVAEXBUFFERCONTEXT pCtx,
-                               PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, bool bEnable)
-{
-    bool bRc = false;
-
-#if 0  /* All callers check this */
-    if (ppdev->bHGSMISupported)
-#endif
-    {
-        void *p = VBoxHGSMIBufferAlloc(pHGSMICtx,
-                                       sizeof (VBVAENABLE_EX),
-                                       HGSMI_CH_VBVA,
-                                       pCtx->u16EnableOp);
-        if (!p)
-        {
-            LogFunc(("HGSMIHeapAlloc failed\n"));
+static int vboxCmdVbvaSubmitHgsmi(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, HGSMIOFFSET offDr)
+{
+    VBoxVideoCmnPortWriteUlong(pHGSMICtx->port, offDr);
+    return VINF_SUCCESS;
+}
+#define vboxCmdVbvaSubmit vboxCmdVbvaSubmitHgsmi
+
+static VBOXCMDVBVA_CTL * vboxCmdVbvaCtlCreate(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, uint32_t cbCtl)
+{
+    Assert(cbCtl >= sizeof (VBOXCMDVBVA_CTL));
+    return (VBOXCMDVBVA_CTL*)VBoxSHGSMICommandAlloc(&pHGSMICtx->heapCtx, cbCtl, HGSMI_CH_VBVA, VBVA_CMDVBVA_CTL);
+}
+
+static void vboxCmdVbvaCtlFree(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, VBOXCMDVBVA_CTL * pCtl)
+{
+    VBoxSHGSMICommandFree(&pHGSMICtx->heapCtx, pCtl);
+}
+
+static int vboxCmdVbvaCtlSubmitSync(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, VBOXCMDVBVA_CTL * pCtl)
+{
+    const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&pHGSMICtx->heapCtx, pCtl);
+    if (!pHdr)
+    {
+        WARN(("VBoxSHGSMICommandPrepSynch returnd NULL"));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pHGSMICtx->heapCtx, pHdr);
+    if (offCmd == HGSMIOFFSET_VOID)
+    {
+        WARN(("VBoxSHGSMICommandOffset returnd NULL"));
+        VBoxSHGSMICommandCancelSynch(&pHGSMICtx->heapCtx, pHdr);
+        return VERR_INVALID_PARAMETER;
+    }
+
+    int rc = vboxCmdVbvaSubmit(pHGSMICtx, offCmd);
+    if (RT_SUCCESS(rc))
+    {
+        rc = VBoxSHGSMICommandDoneSynch(&pHGSMICtx->heapCtx, pHdr);
+        if (RT_SUCCESS(rc))
+        {
+            rc = pCtl->i32Result;
+            if (!RT_SUCCESS(rc))
+                WARN(("pCtl->i32Result %d", pCtl->i32Result));
+
+            return rc;
         }
         else
-        {
-            VBVAENABLE_EX *pEnable = (VBVAENABLE_EX *)p;
-
-            pEnable->Base.u32Flags  = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
-            pEnable->Base.u32Offset = pCtx->offVRAMBuffer;
-            pEnable->Base.i32Result = VERR_NOT_SUPPORTED;
-            pEnable->Base.u32Flags |= VBVA_F_ABSOFFSET;
-
-            VBoxHGSMIBufferSubmit(pHGSMICtx, p);
-
-            if (bEnable)
-            {
-                bRc = RT_SUCCESS(pEnable->Base.i32Result);
-            }
-            else
-            {
-                bRc = true;
-            }
-
-            VBoxHGSMIBufferFree(pHGSMICtx, p);
-        }
-    }
-
-    return bRc;
+            WARN(("VBoxSHGSMICommandDoneSynch returnd %d", rc));
+    }
+    else
+        WARN(("vboxCmdVbvaSubmit returnd %d", rc));
+
+    VBoxSHGSMICommandCancelSynch(&pHGSMICtx->heapCtx, pHdr);
+
+    return rc;
+}
+
+static int vboxCmdVbvaCtlSubmitAsync(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, VBOXCMDVBVA_CTL * pCtl, PFNVBOXSHGSMICMDCOMPLETION_IRQ pfnCompletionIrq, void *pvCompletionIrq)
+{
+    const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq(&pHGSMICtx->heapCtx, pCtl, pfnCompletionIrq, pvCompletionIrq, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
+    if (!pHdr)
+    {
+        WARN(("VBoxSHGSMICommandPrepAsynchIrq returnd NULL"));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pHGSMICtx->heapCtx, pHdr);
+    if (offCmd == HGSMIOFFSET_VOID)
+    {
+        WARN(("VBoxSHGSMICommandOffset returnd NULL"));
+        VBoxSHGSMICommandCancelAsynch(&pHGSMICtx->heapCtx, pHdr);
+        return VERR_INVALID_PARAMETER;
+    }
+
+    int rc = vboxCmdVbvaSubmit(pHGSMICtx, offCmd);
+    if (RT_SUCCESS(rc))
+    {
+        VBoxSHGSMICommandDoneAsynch(&pHGSMICtx->heapCtx, pHdr);
+        return rc;
+    }
+    else
+        WARN(("vboxCmdVbvaSubmit returnd %d", rc));
+
+    VBoxSHGSMICommandCancelAsynch(&pHGSMICtx->heapCtx, pHdr);
+
+    return rc;
+}
+
+static int vboxVBVAExCtlSubmitEnableDisable(PVBVAEXBUFFERCONTEXT pCtx, PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, bool fEnable)
+{
+    VBOXCMDVBVA_CTL_ENABLE *pCtl = (VBOXCMDVBVA_CTL_ENABLE*)vboxCmdVbvaCtlCreate(pHGSMICtx, sizeof (*pCtl));
+    if (!pCtl)
+    {
+        WARN(("vboxCmdVbvaCtlCreate failed"));
+        return VERR_NO_MEMORY;
+    }
+
+    pCtl->Hdr.u32Type = VBOXCMDVBVACTL_TYPE_ENABLE;
+    pCtl->Hdr.i32Result = VERR_NOT_IMPLEMENTED;
+    memset(&pCtl->Enable, 0, sizeof (pCtl->Enable));
+    pCtl->Enable.u32Flags  = fEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
+    pCtl->Enable.u32Offset = pCtx->offVRAMBuffer;
+    pCtl->Enable.i32Result = VERR_NOT_SUPPORTED;
+    pCtl->Enable.u32Flags |= VBVA_F_ABSOFFSET;
+
+    int rc = vboxCmdVbvaCtlSubmitSync(pHGSMICtx, &pCtl->Hdr);
+    if (RT_SUCCESS(rc))
+    {
+        rc = pCtl->Hdr.i32Result;
+        if (!RT_SUCCESS(rc))
+            WARN(("vboxCmdVbvaCtlSubmitSync Disable failed %d", rc));
+    }
+    else
+        WARN(("vboxCmdVbvaCtlSubmitSync returnd %d", rc));
+
+    vboxCmdVbvaCtlFree(pHGSMICtx, &pCtl->Hdr);
+
+    return rc;
 }
 
@@ -189,5 +266,5 @@
         pCtx->pVBVA      = pVBVA;
 
-        bRc = vboxVBVAExInformHost(pCtx, pHGSMICtx, true);
+        bRc = vboxVBVAExCtlSubmitEnableDisable(pCtx, pHGSMICtx, true);
     }
 
@@ -209,5 +286,5 @@
     pCtx->pVBVA             = NULL;
 
-    vboxVBVAExInformHost(pCtx, pHGSMICtx, false);
+    vboxVBVAExCtlSubmitEnableDisable(pCtx, pHGSMICtx, false);
 
     return;
@@ -539,11 +616,9 @@
                                         uint32_t cbBuffer,
                                         PFNVBVAEXBUFFERFLUSH pfnFlush,
-                                        void *pvFlush,
-                                        uint16_t u16EnableOp)
+                                        void *pvFlush)
 {
     memset(pCtx, 0, RT_OFFSETOF(VBVAEXBUFFERCONTEXT, pVBVA));
     pCtx->offVRAMBuffer = offVRAMBuffer;
     pCtx->cbBuffer      = cbBuffer;
-    pCtx->u16EnableOp   = u16EnableOp;
     pCtx->pfnFlush = pfnFlush;
     pCtx->pvFlush = pvFlush;
@@ -824,5 +899,5 @@
     {
         Assert(pVbva->Vbva.pVBVA);
-        VBoxVBVAExSetupBufferContext(&pVbva->Vbva, offBuffer, cbBuffer, voxCmdVbvaFlushCb, pDevExt, VBVA_CMDVBVA_ENABLE);
+        VBoxVBVAExSetupBufferContext(&pVbva->Vbva, offBuffer, cbBuffer, voxCmdVbvaFlushCb, pDevExt);
     }
     else
Index: /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h
===================================================================
--- /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h	(revision 50753)
+++ /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h	(revision 50754)
@@ -77,6 +77,4 @@
      * read it. */
     bool        fHwBufferOverflow;
-    /* VBVA operation used to enable/disable VBVA */
-    uint16_t    u16EnableOp;
     /* the window between indexRecordFirstUncompleted and pVBVA->::indexRecordFirst represents
      * command records processed by the host, but not completed by the guest yet */
@@ -150,6 +148,5 @@
                                         uint32_t cbBuffer,
                                         PFNVBVAEXBUFFERFLUSH pfnFlush,
-                                        void *pvFlush,
-                                        uint16_t u16EnableOp);
+                                        void *pvFlush);
 
 DECLINLINE(uint32_t) VBoxVBVAExGetSize(PVBVAEXBUFFERCONTEXT pCtx)
Index: /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp	(revision 50753)
+++ /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp	(revision 50754)
@@ -1353,5 +1353,5 @@
             switch (chInfo)
             {
-                case VBVA_VBVACMD_CTL:
+                case VBVA_CMDVBVA_CTL:
                 {
                     int rc = VBoxSHGSMICommandProcessCompletion (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, (VBOXSHGSMIHEADER*)pvCmd, TRUE /*bool bIrq*/ , &CtlList);
Index: /trunk/src/VBox/Devices/Graphics/DevVGA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Graphics/DevVGA.cpp	(revision 50753)
+++ /trunk/src/VBox/Devices/Graphics/DevVGA.cpp	(revision 50754)
@@ -5499,4 +5499,7 @@
     LogFlow(("vgaReset\n"));
 
+    if (pThis->pVdma)
+        vboxVDMAReset(pThis->pVdma);
+
 #ifdef VBOX_WITH_HGSMI
     VBVAReset(pThis);
@@ -5949,4 +5952,5 @@
 # endif
 #endif
+    pThis->IVBVACallbacks.pfnCrCtlSubmit = vboxCmdVBVACmdHostCtl;
 
     /*
Index: /trunk/src/VBox/Devices/Graphics/DevVGA.h
===================================================================
--- /trunk/src/VBox/Devices/Graphics/DevVGA.h	(revision 50753)
+++ /trunk/src/VBox/Devices/Graphics/DevVGA.h	(revision 50754)
@@ -625,4 +625,8 @@
 int vboxVDMACrHgsmiControlCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd, int rc);
 # endif
+int vboxCmdVBVACmdHostCtl(PPDMIDISPLAYVBVACALLBACKS pInterface,
+                                                               struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
+                                                               PFNCRCTLCOMPLETION pfnCompletion,
+                                                               void *pvCompletion);
 
 int vboxVBVASaveStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
@@ -634,4 +638,5 @@
 int vboxVDMAConstruct(PVGASTATE pVGAState, uint32_t cPipeElements);
 int vboxVDMADestruct(PVBOXVDMAHOST pVdma);
+int vboxVDMAReset(PVBOXVDMAHOST pVdma);
 void vboxVDMAControl(PVBOXVDMAHOST pVdma, PVBOXVDMA_CTL pCmd, uint32_t cbCmd);
 void vboxVDMACommand(PVBOXVDMAHOST pVdma, PVBOXVDMACBUF_DR pCmd, uint32_t cbCmd);
@@ -640,9 +645,8 @@
 # endif /* VBOX_WITH_VDMA */
 
-int vboxCmdVBVAEnable(PVGASTATE pVGAState, VBVABUFFER *pVBVA);
-int vboxCmdVBVADisable(PVGASTATE pVGAState);
 int vboxCmdVBVACmdSubmit(PVGASTATE pVGAState);
 int vboxCmdVBVACmdFlush(PVGASTATE pVGAState);
 void vboxCmdVBVACmdTimer(PVGASTATE pVGAState);
+int vboxCmdVBVACmdCtl(PVGASTATE pVGAState, VBOXCMDVBVA_CTL *pCtl, uint32_t cbCtl);
 
 #endif /* VBOX_WITH_HGSMI */
Index: /trunk/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp	(revision 50753)
+++ /trunk/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp	(revision 50754)
@@ -1940,4 +1940,30 @@
     switch (u16ChannelInfo)
     {
+        case VBVA_CMDVBVA_SUBMIT:
+        {
+            rc = vboxCmdVBVACmdSubmit(pVGAState);
+            break;
+        }
+        case VBVA_CMDVBVA_FLUSH:
+        {
+            rc =vboxCmdVBVACmdFlush(pVGAState);
+            break;
+        }
+        case VBVA_CMDVBVA_CTL:
+        {
+            if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXCMDVBVA_CTL))
+            {
+                Log(("buffer too small\n"));
+#ifdef DEBUG_misha
+                AssertMsgFailed(("buffer too small\n"));
+#endif
+                rc = VERR_INVALID_PARAMETER;
+                break;
+            }
+
+            VBOXCMDVBVA_CTL *pCtl = (VBOXCMDVBVA_CTL*)VBoxSHGSMIBufferData((PVBOXSHGSMIHEADER)pvBuffer);
+            rc = vboxCmdVBVACmdCtl(pVGAState, pCtl, cbBuffer - VBoxSHGSMIBufferHeaderSize());
+            break;
+        }
 #ifdef VBOX_WITH_VDMA
         case VBVA_VDMA_CMD:
@@ -2253,52 +2279,4 @@
         } break;
 #endif
-
-        case VBVA_CMDVBVA_ENABLE:
-        {
-            if (cbBuffer < sizeof (VBVAENABLE))
-            {
-                rc = VERR_INVALID_PARAMETER;
-                break;
-            }
-
-            VBVAENABLE *pEnable = (VBVAENABLE *)pvBuffer;
-
-            if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE)
-            {
-                uint32_t u32Offset = pEnable->u32Offset;
-                VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, u32Offset);
-
-                if (pVBVA)
-                    rc = vboxCmdVBVAEnable(pVGAState, pVBVA);
-                else
-                {
-                    LogRel(("Invalid VBVABUFFER offset 0x%x!!!\n",
-                         pEnable->u32Offset));
-                    rc = VERR_INVALID_PARAMETER;
-                }
-            }
-            else if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE)
-            {
-                rc = vboxCmdVBVADisable(pVGAState);
-            }
-            else
-            {
-                LogRel(("Invalid VBVA_ENABLE flags 0x%x!!!\n", pEnable->u32Flags));
-                rc = VERR_INVALID_PARAMETER;
-            }
-
-            pEnable->i32Result = rc;
-            break;
-        }
-        case VBVA_CMDVBVA_SUBMIT:
-        {
-            rc = vboxCmdVBVACmdSubmit(pVGAState);
-            break;
-        }
-        case VBVA_CMDVBVA_FLUSH:
-        {
-            rc =vboxCmdVBVACmdFlush(pVGAState);
-            break;
-        }
         case VBVA_SCANLINE_CFG:
         {
Index: /trunk/src/VBox/Devices/Graphics/DevVGA_VDMA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Graphics/DevVGA_VDMA.cpp	(revision 50753)
+++ /trunk/src/VBox/Devices/Graphics/DevVGA_VDMA.cpp	(revision 50754)
@@ -21,4 +21,5 @@
 #include <iprt/mem.h>
 #include <iprt/asm.h>
+#include <iprt/list.h>
 
 #include "DevVGA.h"
@@ -26,4 +27,13 @@
 
 #include <VBox/VBoxVideo3D.h>
+#include <VBox/VBoxVideoHost3D.h>
+
+#ifdef DEBUG_misha
+# define VBOXVDBG_MEMCACHE_DISABLE
+#endif
+
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+# include <iprt/memcache.h>
+#endif
 
 #ifdef DEBUG_misha
@@ -37,56 +47,15 @@
     } while (0)
 
-#ifdef VBOX_VDMA_WITH_WORKERTHREAD
-typedef enum
-{
-    VBOXVDMAPIPE_STATE_CLOSED    = 0,
-    VBOXVDMAPIPE_STATE_CREATED   = 1,
-    VBOXVDMAPIPE_STATE_OPENNED   = 2,
-    VBOXVDMAPIPE_STATE_CLOSING   = 3
-} VBOXVDMAPIPE_STATE;
-
-typedef struct VBOXVDMAPIPE
-{
+#define VBOXVDMATHREAD_STATE_TERMINATED     0
+#define VBOXVDMATHREAD_STATE_CREATED        1
+#define VBOXVDMATHREAD_STATE_TERMINATING    2
+
+typedef struct VBOXVDMATHREAD
+{
+    RTTHREAD hWorkerThread;
     RTSEMEVENT hEvent;
-    /* critical section for accessing pipe properties */
-    RTCRITSECT hCritSect;
-    VBOXVDMAPIPE_STATE enmState;
-    /* true iff the other end needs Event notification */
-    bool bNeedNotify;
-} VBOXVDMAPIPE, *PVBOXVDMAPIPE;
-
-typedef enum
-{
-    VBOXVDMAPIPE_CMD_TYPE_UNDEFINED = 0,
-    VBOXVDMAPIPE_CMD_TYPE_DMACMD    = 1,
-    VBOXVDMAPIPE_CMD_TYPE_DMACTL    = 2
-} VBOXVDMAPIPE_CMD_TYPE;
-
-typedef struct VBOXVDMAPIPE_CMD_BODY
-{
-    VBOXVDMAPIPE_CMD_TYPE enmType;
-    union
-    {
-        PVBOXVDMACBUF_DR pDr;
-        PVBOXVDMA_CTL    pCtl;
-        void            *pvCmd;
-    } u;
-}VBOXVDMAPIPE_CMD_BODY, *PVBOXVDMAPIPE_CMD_BODY;
-
-typedef struct VBOXVDMAPIPE_CMD
-{
-    HGSMILISTENTRY Entry;
-    VBOXVDMAPIPE_CMD_BODY Cmd;
-} VBOXVDMAPIPE_CMD, *PVBOXVDMAPIPE_CMD;
-
-#define VBOXVDMAPIPE_CMD_FROM_ENTRY(_pE)  ( (PVBOXVDMAPIPE_CMD)((uint8_t *)(_pE) - RT_OFFSETOF(VBOXVDMAPIPE_CMD, Entry)) )
-
-typedef struct VBOXVDMAPIPE_CMD_POOL
-{
-    HGSMILIST List;
-    uint32_t cCmds;
-    VBOXVDMAPIPE_CMD aCmds[1];
-} VBOXVDMAPIPE_CMD_POOL, *PVBOXVDMAPIPE_CMD_POOL;
-#endif
+    RTSEMEVENT hClientEvent;
+    volatile uint32_t u32State;
+} VBOXVDMATHREAD, *PVBOXVDMATHREAD;
 
 
@@ -94,33 +63,70 @@
  *
  *   submitter   |    processor
- *   STOPPED
- *      |
- *      |
- *      >
+ *
  *  LISTENING   --->  PROCESSING
- *      ^               _/
- *      |             _/
- *      |           _/
- *      |         _/
- *      |       _/
- *      |     _/
- *      |    /
- *      <   >
- *     PAUSED
  *
  *  */
-#define VBVAEXHOSTCONTEXT_STATE_STOPPED        0
-#define VBVAEXHOSTCONTEXT_STATE_LISTENING      1
-#define VBVAEXHOSTCONTEXT_STATE_PROCESSING     2
-#define VBVAEXHOSTCONTEXT_STATE_PAUSED         3
+#define VBVAEXHOSTCONTEXT_STATE_LISTENING      0
+#define VBVAEXHOSTCONTEXT_STATE_PROCESSING     1
+
+#define VBVAEXHOSTCONTEXT_ESTATE_DISABLED     -1
+#define VBVAEXHOSTCONTEXT_ESTATE_PAUSED        0
+#define VBVAEXHOSTCONTEXT_ESTATE_ENABLED       1
 
 typedef struct VBVAEXHOSTCONTEXT
 {
     VBVABUFFER *pVBVA;
-    uint32_t cbCurData;
-    volatile uint32_t u32State;
-    volatile uint32_t u32Pause;
-    volatile uint32_t u32cOtherCommands;
+    volatile int32_t i32State;
+    volatile int32_t i32EnableState;
+    volatile uint32_t u32cCtls;
+    /* critical section for accessing ctl lists */
+    RTCRITSECT CltCritSect;
+    RTLISTNODE GuestCtlList;
+    RTLISTNODE HostCtlList;
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+    RTMEMCACHE CtlCache;
+#endif
 } VBVAEXHOSTCONTEXT;
+
+typedef enum
+{
+    VBVAEXHOSTCTL_TYPE_UNDEFINED = 0,
+    VBVAEXHOSTCTL_TYPE_HH_INTERNAL_PAUSE,
+    VBVAEXHOSTCTL_TYPE_HH_INTERNAL_RESUME,
+    VBVAEXHOSTCTL_TYPE_HH_ENABLE,
+    VBVAEXHOSTCTL_TYPE_HH_TERM,
+    VBVAEXHOSTCTL_TYPE_HH_RESET,
+    VBVAEXHOSTCTL_TYPE_HH_SAVESTATE,
+    VBVAEXHOSTCTL_TYPE_HH_LOADSTATE,
+    VBVAEXHOSTCTL_TYPE_HH_BE_OPAQUE,
+    VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE,
+    VBVAEXHOSTCTL_TYPE_GH_ENABLE_DISABLE
+} VBVAEXHOSTCTL_TYPE;
+
+struct VBVAEXHOSTCTL;
+
+typedef DECLCALLBACKPTR(void, PFNVBVAEXHOSTCTL_COMPLETE)(VBVAEXHOSTCONTEXT *pVbva, struct VBVAEXHOSTCTL *pCtl, int rc, void *pvComplete);
+
+typedef struct VBVAEXHOSTCTL
+{
+    RTLISTNODE Node;
+    VBVAEXHOSTCTL_TYPE enmType;
+    union
+    {
+        struct
+        {
+            uint8_t * pu8Cmd;
+            uint32_t cbCmd;
+        } cmd;
+
+        struct
+        {
+            PSSMHANDLE pSSM;
+            uint32_t u32Version;
+        } state;
+    } u;
+    PFNVBVAEXHOSTCTL_COMPLETE pfnComplete;
+    void *pvComplete;
+} VBVAEXHOSTCTL;
 
 /* VBoxVBVAExHP**, i.e. processor functions, can NOT be called concurrently with each other,
@@ -128,6 +134,15 @@
  * Can only be called be the processor, i.e. the entity that acquired the processor state by direct or indirect call to the VBoxVBVAExHSCheckCommands
  * see mor edetailed comments in headers for function definitions */
-static bool VBoxVBVAExHPCmdCheckRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva);
-static int VBoxVBVAExHPCmdGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd);
+typedef enum
+{
+    VBVAEXHOST_DATA_TYPE_NO_DATA = 0,
+    VBVAEXHOST_DATA_TYPE_CMD,
+    VBVAEXHOST_DATA_TYPE_HOSTCTL,
+    VBVAEXHOST_DATA_TYPE_GUESTCTL,
+} VBVAEXHOST_DATA_TYPE;
+static VBVAEXHOST_DATA_TYPE VBoxVBVAExHPDataGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd);
+
+static void VBoxVBVAExHPDataCompleteCmd(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint32_t cbCmd);
+static void VBoxVBVAExHPDataCompleteCtl(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL *pCtl, int rc);
 
 /* VBoxVBVAExHP**, i.e. processor functions, can NOT be called concurrently with each other,
@@ -135,5 +150,5 @@
 static int VBoxVBVAExHSCheckCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva);
 
-static void VBoxVBVAExHSInit(struct VBVAEXHOSTCONTEXT *pCmdVbva);
+static int VBoxVBVAExHSInit(struct VBVAEXHOSTCONTEXT *pCmdVbva);
 static int VBoxVBVAExHSEnable(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVABUFFER *pVBVA);
 static int VBoxVBVAExHSDisable(struct VBVAEXHOSTCONTEXT *pCmdVbva);
@@ -142,4 +157,507 @@
 static int VBoxVBVAExHSLoadState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM, uint32_t u32Version);
 
+static VBVAEXHOSTCTL* VBoxVBVAExHCtlAlloc(VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+    return (VBVAEXHOSTCONTEXT*)RTMemCacheAlloc(pCmdVbva->CtlCache);
+#else
+    return (VBVAEXHOSTCTL*)RTMemAlloc(sizeof (VBVAEXHOSTCTL));
+#endif
+}
+
+static void VBoxVBVAExHCtlFree(VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL *pCtl)
+{
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+    RTMemCacheFree(pCmdVbva->CtlCache, pCtl);
+#else
+    RTMemFree(pCtl);
+#endif
+}
+
+static VBVAEXHOSTCTL* VBoxVBVAExHCtlCreate(VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL_TYPE enmType)
+{
+    VBVAEXHOSTCTL* pCtl = VBoxVBVAExHCtlAlloc(pCmdVbva);
+    if (!pCtl)
+    {
+        WARN(("VBoxVBVAExHCtlAlloc failed\n"));
+        return NULL;
+    }
+
+    pCtl->enmType = enmType;
+    return pCtl;
+}
+
+static int vboxVBVAExHSProcessorAcquire(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    Assert(pCmdVbva->i32State >= VBVAEXHOSTCONTEXT_STATE_LISTENING);
+
+    if (ASMAtomicCmpXchgS32(&pCmdVbva->i32State, VBVAEXHOSTCONTEXT_STATE_PROCESSING, VBVAEXHOSTCONTEXT_STATE_LISTENING))
+            return VINF_SUCCESS;
+    return VERR_SEM_BUSY;
+}
+
+static VBVAEXHOSTCTL* vboxVBVAExHPCheckCtl(struct VBVAEXHOSTCONTEXT *pCmdVbva, bool *pfHostCtl, bool fHostOnlyMode)
+{
+    Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
+
+    if(!fHostOnlyMode && !ASMAtomicUoReadU32(&pCmdVbva->u32cCtls))
+        return NULL;
+
+    int rc = RTCritSectEnter(&pCmdVbva->CltCritSect);
+    if (RT_SUCCESS(rc))
+    {
+        VBVAEXHOSTCTL* pCtl = RTListGetFirst(&pCmdVbva->HostCtlList, VBVAEXHOSTCTL, Node);
+        if (pCtl)
+            *pfHostCtl = true;
+        else if (!fHostOnlyMode)
+        {
+            if (ASMAtomicUoReadS32(&pCmdVbva->i32EnableState) > VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
+            {
+                pCtl = RTListGetFirst(&pCmdVbva->GuestCtlList, VBVAEXHOSTCTL, Node);
+                /* pCtl can not be null here since pCmdVbva->u32cCtls is not null,
+                 * and there are no HostCtl commands*/
+                Assert(pCtl);
+                *pfHostCtl = false;
+            }
+        }
+
+        if (pCtl)
+        {
+            RTListNodeRemove(&pCtl->Node);
+            ASMAtomicDecU32(&pCmdVbva->u32cCtls);
+        }
+
+        RTCritSectLeave(&pCmdVbva->CltCritSect);
+
+        return pCtl;
+    }
+    else
+        WARN(("RTCritSectEnter failed %d\n", rc));
+
+    return NULL;
+}
+
+static VBVAEXHOSTCTL* VBoxVBVAExHPCheckHostCtlOnDisable(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    bool fHostCtl;
+    return vboxVBVAExHPCheckCtl(pCmdVbva, &fHostCtl, true);
+}
+
+
+static bool vboxVBVAExHPCheckProcessCtlInternal(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL* pCtl)
+{
+    switch (pCtl->enmType)
+    {
+        case VBVAEXHOSTCTL_TYPE_HH_INTERNAL_PAUSE:
+            if (pCmdVbva->i32EnableState > VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
+                ASMAtomicWriteS32(&pCmdVbva->i32EnableState, VBVAEXHOSTCONTEXT_ESTATE_PAUSED);
+            return true;
+        case VBVAEXHOSTCTL_TYPE_HH_INTERNAL_RESUME:
+            if (pCmdVbva->i32EnableState == VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
+                ASMAtomicWriteS32(&pCmdVbva->i32EnableState, VBVAEXHOSTCONTEXT_ESTATE_ENABLED);
+            return true;
+        default:
+            return false;
+    }
+}
+
+static void vboxVBVAExHPProcessorRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
+
+    ASMAtomicWriteS32(&pCmdVbva->i32State, VBVAEXHOSTCONTEXT_STATE_LISTENING);
+}
+
+static void vboxVBVAExHPHgEventSet(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
+    if (pCmdVbva->pVBVA)
+        ASMAtomicOrU32(&pCmdVbva->pVBVA->hostFlags.u32HostEvents, VBVA_F_STATE_PROCESSING);
+}
+
+static void vboxVBVAExHPHgEventClear(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
+    if (pCmdVbva->pVBVA)
+        ASMAtomicAndU32(&pCmdVbva->pVBVA->hostFlags.u32HostEvents, ~VBVA_F_STATE_PROCESSING);
+}
+
+static int vboxVBVAExHPCmdGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
+{
+    Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
+    Assert(pCmdVbva->i32EnableState > VBVAEXHOSTCONTEXT_ESTATE_PAUSED);
+
+    VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
+
+    uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
+    uint32_t indexRecordFree = pVBVA->indexRecordFree;
+
+    Log(("first = %d, free = %d\n",
+                   indexRecordFirst, indexRecordFree));
+
+    if (indexRecordFirst == indexRecordFree)
+    {
+        /* No records to process. Return without assigning output variables. */
+        return VINF_EOF;
+    }
+
+    uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVBVA->aRecords[indexRecordFirst].cbRecord);
+
+    /* A new record need to be processed. */
+    if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
+    {
+        /* the record is being recorded, try again */
+        return VINF_TRY_AGAIN;
+    }
+
+    uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
+
+    if (!cbRecord)
+    {
+        /* the record is being recorded, try again */
+        return VINF_TRY_AGAIN;
+    }
+
+    /* we should not get partial commands here actually */
+    Assert(cbRecord);
+
+    /* The size of largest contiguous chunk in the ring biffer. */
+    uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
+
+    /* The pointer to data in the ring buffer. */
+    uint8_t *pSrc = &pVBVA->au8Data[pVBVA->off32Data];
+
+    /* Fetch or point the data. */
+    if (u32BytesTillBoundary >= cbRecord)
+    {
+        /* The command does not cross buffer boundary. Return address in the buffer. */
+        *ppCmd = pSrc;
+        *pcbCmd = cbRecord;
+        return VINF_SUCCESS;
+    }
+
+    LogRel(("CmdVbva: cross-bound writes unsupported\n"));
+    return VERR_INVALID_STATE;
+}
+
+static void VBoxVBVAExHPDataCompleteCmd(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint32_t cbCmd)
+{
+    VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
+    pVBVA->off32Data = (pVBVA->off32Data + cbCmd) % pVBVA->cbData;
+
+    pVBVA->indexRecordFirst = (pVBVA->indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
+}
+
+static void VBoxVBVAExHPDataCompleteCtl(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL *pCtl, int rc)
+{
+    if (pCtl->pfnComplete)
+        pCtl->pfnComplete(pCmdVbva, pCtl, rc, pCtl->pvComplete);
+    else
+        VBoxVBVAExHCtlFree(pCmdVbva, pCtl);
+}
+
+static VBVAEXHOST_DATA_TYPE vboxVBVAExHPDataGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
+{
+    Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
+    VBVAEXHOSTCTL*pCtl;
+    bool fHostClt;
+
+    for(;;)
+    {
+        pCtl = vboxVBVAExHPCheckCtl(pCmdVbva, &fHostClt, false);
+        if (pCtl)
+        {
+            if (fHostClt)
+            {
+                if (!vboxVBVAExHPCheckProcessCtlInternal(pCmdVbva, pCtl))
+                {
+                    *ppCmd = (uint8_t*)pCtl;
+                    *pcbCmd = sizeof (*pCtl);
+                    return VBVAEXHOST_DATA_TYPE_HOSTCTL;
+                }
+            }
+            else
+            {
+                *ppCmd = (uint8_t*)pCtl;
+                *pcbCmd = sizeof (*pCtl);
+                return VBVAEXHOST_DATA_TYPE_GUESTCTL;
+            }
+        }
+
+        if (ASMAtomicUoReadS32(&pCmdVbva->i32EnableState) <= VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
+            return VBVAEXHOST_DATA_TYPE_NO_DATA;
+
+        int rc = vboxVBVAExHPCmdGet(pCmdVbva, ppCmd, pcbCmd);
+        switch (rc)
+        {
+            case VINF_SUCCESS:
+                return VBVAEXHOST_DATA_TYPE_CMD;
+            case VINF_EOF:
+                return VBVAEXHOST_DATA_TYPE_NO_DATA;
+            case VINF_TRY_AGAIN:
+                RTThreadSleep(1);
+                continue;
+            default:
+                /* this is something really unexpected, i.e. most likely guest has written something incorrect to the VBVA buffer */
+                WARN(("Warning: vboxVBVAExHCmdGet returned unexpected status %d\n", rc));
+                return VBVAEXHOST_DATA_TYPE_NO_DATA;
+        }
+    }
+
+    WARN(("Warning: VBoxVBVAExHCmdGet unexpected state\n"));
+    return VBVAEXHOST_DATA_TYPE_NO_DATA;
+}
+
+static VBVAEXHOST_DATA_TYPE VBoxVBVAExHPDataGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
+{
+    VBVAEXHOST_DATA_TYPE enmType = vboxVBVAExHPDataGet(pCmdVbva, ppCmd, pcbCmd);
+    if (enmType == VBVAEXHOST_DATA_TYPE_NO_DATA)
+    {
+        vboxVBVAExHPHgEventClear(pCmdVbva);
+        vboxVBVAExHPProcessorRelease(pCmdVbva);
+        /* we need to prevent racing between us clearing the flag and command check/submission thread, i.e.
+         * 1. we check the queue -> and it is empty
+         * 2. submitter adds command to the queue
+         * 3. submitter checks the "processing" -> and it is true , thus it does not submit a notification
+         * 4. we clear the "processing" state
+         * 5. ->here we need to re-check the queue state to ensure we do not leak the notification of the above command
+         * 6. if the queue appears to be not-empty set the "processing" state back to "true"
+         **/
+        int rc = vboxVBVAExHSProcessorAcquire(pCmdVbva);
+        if (RT_SUCCESS(rc))
+        {
+            /* we are the processor now */
+            enmType = vboxVBVAExHPDataGet(pCmdVbva, ppCmd, pcbCmd);
+            if (enmType == VBVAEXHOST_DATA_TYPE_NO_DATA)
+            {
+                vboxVBVAExHPProcessorRelease(pCmdVbva);
+                return VBVAEXHOST_DATA_TYPE_NO_DATA;
+            }
+
+            vboxVBVAExHPHgEventSet(pCmdVbva);
+        }
+    }
+
+    return enmType;
+}
+
+DECLINLINE(bool) vboxVBVAExHSHasCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
+
+    if (pVBVA)
+    {
+        uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
+        uint32_t indexRecordFree = pVBVA->indexRecordFree;
+
+        if (indexRecordFirst != indexRecordFree)
+            return true;
+    }
+
+    return !!ASMAtomicReadU32(&pCmdVbva->u32cCtls);
+}
+
+/* Checks whether the new commands are ready for processing
+ * @returns
+ *   VINF_SUCCESS - there are commands are in a queue, and the given thread is now the processor (i.e. typically it would delegate processing to a worker thread)
+ *   VINF_EOF - no commands in a queue
+ *   VINF_ALREADY_INITIALIZED - another thread already processing the commands
+ *   VERR_INVALID_STATE - the VBVA is paused or pausing */
+static int VBoxVBVAExHSCheckCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    int rc = vboxVBVAExHSProcessorAcquire(pCmdVbva);
+    if (RT_SUCCESS(rc))
+    {
+        /* we are the processor now */
+        if (vboxVBVAExHSHasCommands(pCmdVbva))
+        {
+            vboxVBVAExHPHgEventSet(pCmdVbva);
+            return VINF_SUCCESS;
+        }
+
+        vboxVBVAExHPProcessorRelease(pCmdVbva);
+        return VINF_EOF;
+    }
+    if (rc == VERR_SEM_BUSY)
+        return VINF_ALREADY_INITIALIZED;
+    return VERR_INVALID_STATE;
+}
+
+static int VBoxVBVAExHSInit(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    memset(pCmdVbva, 0, sizeof (*pCmdVbva));
+    int rc = RTCritSectInit(&pCmdVbva->CltCritSect);
+    if (RT_SUCCESS(rc))
+    {
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+        rc = RTMemCacheCreate(&pCmdVbva->CtlCache, sizeof (VBVAEXHOSTCTL),
+                                0, /* size_t cbAlignment */
+                                UINT32_MAX, /* uint32_t cMaxObjects */
+                                NULL, /* PFNMEMCACHECTOR pfnCtor*/
+                                NULL, /* PFNMEMCACHEDTOR pfnDtor*/
+                                NULL, /* void *pvUser*/
+                                0 /* uint32_t fFlags*/
+                                );
+        if (RT_SUCCESS(rc))
+#endif
+        {
+            RTListInit(&pCmdVbva->GuestCtlList);
+            RTListInit(&pCmdVbva->HostCtlList);
+            pCmdVbva->i32State = VBVAEXHOSTCONTEXT_STATE_PROCESSING;
+            pCmdVbva->i32EnableState = VBVAEXHOSTCONTEXT_ESTATE_DISABLED;
+            return VINF_SUCCESS;
+        }
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+        else
+            WARN(("RTMemCacheCreate failed %d\n", rc));
+#endif
+    }
+    else
+        WARN(("RTCritSectInit failed %d\n", rc));
+
+    return rc;
+}
+
+DECLINLINE(bool) VBoxVBVAExHSIsEnabled(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    return (ASMAtomicUoReadS32(&pCmdVbva->i32EnableState) >= VBVAEXHOSTCONTEXT_ESTATE_PAUSED);
+}
+
+static int VBoxVBVAExHSEnable(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVABUFFER *pVBVA)
+{
+    if (VBoxVBVAExHSIsEnabled(pCmdVbva))
+        return VINF_ALREADY_INITIALIZED;
+
+    pCmdVbva->pVBVA = pVBVA;
+    pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
+    ASMAtomicWriteS32(&pCmdVbva->i32EnableState, VBVAEXHOSTCONTEXT_ESTATE_ENABLED);
+    return VINF_SUCCESS;
+}
+
+static int VBoxVBVAExHSDisable(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    if (!VBoxVBVAExHSIsEnabled(pCmdVbva))
+        return VINF_SUCCESS;
+
+    ASMAtomicWriteS32(&pCmdVbva->i32EnableState, VBVAEXHOSTCONTEXT_ESTATE_DISABLED);
+    return VINF_SUCCESS;
+}
+
+static void VBoxVBVAExHSTerm(struct VBVAEXHOSTCONTEXT *pCmdVbva)
+{
+    /* ensure the processor is stopped */
+    Assert(pCmdVbva->i32State >= VBVAEXHOSTCONTEXT_STATE_LISTENING);
+
+    /* ensure no one tries to submit the command */
+    if (pCmdVbva->pVBVA)
+        pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
+
+    Assert(RTListIsEmpty(&pCmdVbva->GuestCtlList));
+    Assert(RTListIsEmpty(&pCmdVbva->HostCtlList));
+
+    RTCritSectDelete(&pCmdVbva->CltCritSect);
+
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+    RTMemCacheDestroy(pCmdVbva->CtlCache);
+#endif
+
+    memset(pCmdVbva, 0, sizeof (*pCmdVbva));
+}
+
+/* Saves state
+ * @returns - same as VBoxVBVAExHSCheckCommands, or failure on load state fail
+ */
+static int VBoxVBVAExHSSaveState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM)
+{
+    int rc;
+
+    int32_t i32EnableState = ASMAtomicUoReadS32(&pCmdVbva->i32EnableState);
+    if (i32EnableState >= VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
+    {
+        if (i32EnableState != VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
+        {
+            WARN(("vbva not paused\n"));
+            return VERR_INVALID_STATE;
+        }
+
+        rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pCmdVbva->pVBVA) - pu8VramBase));
+        AssertRCReturn(rc, rc);
+        return VINF_SUCCESS;
+    }
+
+    rc = SSMR3PutU32(pSSM, 0xffffffff);
+    AssertRCReturn(rc, rc);
+
+    return VINF_SUCCESS;
+}
+
+typedef enum
+{
+    VBVAEXHOSTCTL_SOURCE_GUEST = 0,
+    VBVAEXHOSTCTL_SOURCE_HOST_ANY,
+    VBVAEXHOSTCTL_SOURCE_HOST_ENABLED
+} VBVAEXHOSTCTL_SOURCE;
+
+
+static int VBoxVBVAExHCtlSubmit(VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL* pCtl, VBVAEXHOSTCTL_SOURCE enmSource, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
+{
+    if ((enmSource == VBVAEXHOSTCTL_SOURCE_HOST_ENABLED) && !VBoxVBVAExHSIsEnabled(pCmdVbva))
+    {
+        WARN(("cmd vbva not enabled\n"));
+        return VERR_INVALID_STATE;
+    }
+
+    pCtl->pfnComplete = pfnComplete;
+    pCtl->pvComplete = pvComplete;
+
+    int rc = RTCritSectEnter(&pCmdVbva->CltCritSect);
+    if (RT_SUCCESS(rc))
+    {
+        if (enmSource > VBVAEXHOSTCTL_SOURCE_GUEST)
+        {
+            if ((enmSource == VBVAEXHOSTCTL_SOURCE_HOST_ENABLED) && !VBoxVBVAExHSIsEnabled(pCmdVbva))
+            {
+                WARN(("cmd vbva not enabled\n"));
+                RTCritSectLeave(&pCmdVbva->CltCritSect);
+                return VERR_INVALID_STATE;
+            }
+            RTListAppend(&pCmdVbva->HostCtlList, &pCtl->Node);
+        }
+        else
+            RTListAppend(&pCmdVbva->GuestCtlList, &pCtl->Node);
+
+        ASMAtomicIncU32(&pCmdVbva->u32cCtls);
+
+        RTCritSectLeave(&pCmdVbva->CltCritSect);
+
+        rc = VBoxVBVAExHSCheckCommands(pCmdVbva);
+    }
+    else
+        WARN(("RTCritSectEnter failed %d\n", rc));
+
+    return rc;
+}
+
+
+/* Loads state
+ * @returns - same as VBoxVBVAExHSCheckCommands, or failure on load state fail
+ */
+static int VBoxVBVAExHSLoadState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM, uint32_t u32Version)
+{
+    AssertMsgFailed(("implement!\n"));
+    uint32_t u32;
+    int rc = SSMR3GetU32(pSSM, &u32);
+    AssertRCReturn(rc, rc);
+    if (u32 != 0xffffffff)
+    {
+        VBVABUFFER *pVBVA = (VBVABUFFER*)pu8VramBase + u32;
+        rc = VBoxVBVAExHSEnable(pCmdVbva, pVBVA);
+        AssertRCReturn(rc, rc);
+        return VBoxVBVAExHSCheckCommands(pCmdVbva);
+    }
+
+    return VINF_SUCCESS;
+}
+
 typedef struct VBOXVDMAHOST
 {
@@ -147,15 +665,117 @@
     PVGASTATE pVGAState;
     VBVAEXHOSTCONTEXT CmdVbva;
+    VBOXVDMATHREAD Thread;
+    VBOXCRCMD_SVRINFO CrSrvInfo;
+    VBVAEXHOSTCTL* pCurRemainingHostCtl;
 #ifdef VBOX_VDMA_WITH_WATCHDOG
     PTMTIMERR3 WatchDogTimer;
 #endif
-#ifdef VBOX_VDMA_WITH_WORKERTHREAD
-    VBOXVDMAPIPE Pipe;
-    HGSMILIST PendingList;
-    RTTHREAD hWorkerThread;
-    VBOXVDMAPIPE_CMD_POOL CmdPool;
-#endif
 } VBOXVDMAHOST, *PVBOXVDMAHOST;
 
+int VBoxVDMAThreadNotifyConstructSucceeded(PVBOXVDMATHREAD pThread)
+{
+    Assert(pThread->u32State == VBOXVDMATHREAD_STATE_TERMINATED);
+    int rc = RTSemEventSignal(pThread->hClientEvent);
+    AssertRC(rc);
+    if (RT_SUCCESS(rc))
+    {
+        pThread->u32State = VBOXVDMATHREAD_STATE_CREATED;
+        return VINF_SUCCESS;
+    }
+    return rc;
+}
+
+int VBoxVDMAThreadNotifyConstructFailed(PVBOXVDMATHREAD pThread)
+{
+    Assert(pThread->u32State == VBOXVDMATHREAD_STATE_TERMINATED);
+    int rc = RTSemEventSignal(pThread->hClientEvent);
+    AssertRC(rc);
+    if (RT_SUCCESS(rc))
+        return VINF_SUCCESS;
+    return rc;
+}
+
+DECLINLINE(bool) VBoxVDMAThreadIsTerminating(PVBOXVDMATHREAD pThread)
+{
+    return ASMAtomicUoReadU32(&pThread->u32State) == VBOXVDMATHREAD_STATE_TERMINATING;
+}
+
+int VBoxVDMAThreadCreate(PVBOXVDMATHREAD pThread, PFNRTTHREAD pfnThread, void *pvThread)
+{
+    int rc = RTSemEventCreate(&pThread->hEvent);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTSemEventCreate(&pThread->hClientEvent);
+        if (RT_SUCCESS(rc))
+        {
+            pThread->u32State = VBOXVDMATHREAD_STATE_TERMINATED;
+            rc = RTThreadCreate(&pThread->hWorkerThread, pfnThread, pvThread, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "VDMA");
+            if (RT_SUCCESS(rc))
+            {
+                rc = RTSemEventWait(pThread->hClientEvent, RT_INDEFINITE_WAIT);
+                if (RT_SUCCESS(rc))
+                {
+                    if (pThread->u32State == VBOXVDMATHREAD_STATE_CREATED)
+                        return VINF_SUCCESS;
+                    WARN(("thread routine failed the initialization\n"));
+                    rc = VERR_INVALID_STATE;
+                }
+                else
+                    WARN(("RTSemEventWait failed %d\n", rc));
+
+                RTThreadWait(pThread->hWorkerThread, RT_INDEFINITE_WAIT, NULL);
+            }
+            else
+                WARN(("RTThreadCreate failed %d\n", rc));
+
+            RTSemEventDestroy(pThread->hClientEvent);
+        }
+        else
+            WARN(("RTSemEventCreate failed %d\n", rc));
+
+        RTSemEventDestroy(pThread->hEvent);
+    }
+    else
+        WARN(("RTSemEventCreate failed %d\n", rc));
+
+    return rc;
+}
+
+DECLINLINE(int) VBoxVDMAThreadEventNotify(PVBOXVDMATHREAD pThread)
+{
+    int rc = RTSemEventSignal(pThread->hEvent);
+    AssertRC(rc);
+    return rc;
+}
+
+DECLINLINE(int) VBoxVDMAThreadEventWait(PVBOXVDMATHREAD pThread, RTMSINTERVAL cMillies)
+{
+    int rc = RTSemEventWait(pThread->hEvent, cMillies);
+    AssertRC(rc);
+    return rc;
+}
+
+void VBoxVDMAThreadMarkTerminating(PVBOXVDMATHREAD pThread)
+{
+    Assert(pThread->u32State == VBOXVDMATHREAD_STATE_CREATED);
+    ASMAtomicWriteU32(&pThread->u32State, VBOXVDMATHREAD_STATE_TERMINATING);
+}
+
+void VBoxVDMAThreadTerm(PVBOXVDMATHREAD pThread)
+{
+    int rc;
+    if (ASMAtomicReadU32(&pThread->u32State) != VBOXVDMATHREAD_STATE_TERMINATING)
+    {
+        VBoxVDMAThreadMarkTerminating(pThread);
+        rc = VBoxVDMAThreadEventNotify(pThread);
+        AssertRC(rc);
+    }
+    rc = RTThreadWait(pThread->hWorkerThread, RT_INDEFINITE_WAIT, NULL);
+    AssertRC(rc);
+    RTSemEventDestroy(pThread->hClientEvent);
+    RTSemEventDestroy(pThread->hEvent);
+}
+
+static int vdmaVBVACtlSubmitSync(PVBOXVDMAHOST pVdma, VBVAEXHOSTCTL* pCtl, VBVAEXHOSTCTL_SOURCE enmSource);
 
 #ifdef VBOX_WITH_CRHGSMI
@@ -248,5 +868,5 @@
     if(RT_SUCCESS(rc))
     {
-        rc = vboxVDMACrCtlPostAsync (pVGAState, pCmd, cbCmd, vboxVDMACrCtlCbSetEvent, (void*)hComplEvent);
+        rc = vboxVDMACrCtlPostAsync(pVGAState, pCmd, cbCmd, vboxVDMACrCtlCbSetEvent, (void*)hComplEvent);
 #ifdef DEBUG_misha
         AssertRC(rc);
@@ -270,9 +890,271 @@
 }
 
-static void vboxVDMACrCmdNotifyPerform(struct VBOXVDMAHOST *pVdma)
-{
+typedef struct VDMA_VBVA_CTL_CYNC_COMPLETION
+{
+    int rc;
+    RTSEMEVENT hEvent;
+} VDMA_VBVA_CTL_CYNC_COMPLETION;
+
+static DECLCALLBACK(void) vboxVDMACrHgcmSubmitSyncCompletion(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
+{
+    VDMA_VBVA_CTL_CYNC_COMPLETION *pData = (VDMA_VBVA_CTL_CYNC_COMPLETION*)pvCompletion;
+    pData->rc = rc;
+    rc = RTSemEventSignal(pData->hEvent);
+    if (!RT_SUCCESS(rc))
+        WARN(("RTSemEventSignal failed %d\n", rc));
+}
+
+static int vboxVDMACrHgcmSubmitSync(struct VBOXVDMAHOST *pVdma, VBOXCRCMDCTL* pCtl, uint32_t cbCtl)
+{
+    VDMA_VBVA_CTL_CYNC_COMPLETION Data;
+    Data.rc = VERR_NOT_IMPLEMENTED;
+    int rc = RTSemEventCreate(&Data.hEvent);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("RTSemEventCreate failed %d\n", rc));
+        return rc;
+    }
+
     PVGASTATE pVGAState = pVdma->pVGAState;
-    pVGAState->pDrv->pfnCrCmdNotifyCmds(pVGAState->pDrv);
-}
+    rc = pVGAState->pDrv->pfnCrHgcmCtlSubmit(pVGAState->pDrv, pCtl, cbCtl, vboxVDMACrHgcmSubmitSyncCompletion, &Data);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTSemEventWait(Data.hEvent, RT_INDEFINITE_WAIT);
+        if (RT_SUCCESS(rc))
+        {
+            rc = Data.rc;
+            if (!RT_SUCCESS(rc))
+            {
+                WARN(("pfnCrHgcmCtlSubmit command failed %d\n", rc));
+            }
+
+        }
+        else
+            WARN(("RTSemEventWait failed %d\n", rc));
+    }
+    else
+        WARN(("pfnCrHgcmCtlSubmit failed %d\n", rc));
+
+
+    RTSemEventDestroy(Data.hEvent);
+
+    return rc;
+}
+
+static DECLCALLBACK(VBOXCRCMDCTL*) vboxVDMACrHgcmHandleEnableRemainingHostCommand(HVBOXCRCMDCTL_REMAINING_HOST_COMMAND hClient, uint32_t *pcbCtl, int prevCmdRc)
+{
+    struct VBOXVDMAHOST *pVdma = hClient;
+    if (!pVdma->pCurRemainingHostCtl)
+    {
+        /* disable VBVA, all subsequent host commands will go HGCM way */
+        VBoxVBVAExHSDisable(&pVdma->CmdVbva);
+    }
+    else
+    {
+        VBoxVBVAExHPDataCompleteCtl(&pVdma->CmdVbva, pVdma->pCurRemainingHostCtl, prevCmdRc);
+    }
+
+    pVdma->pCurRemainingHostCtl = VBoxVBVAExHPCheckHostCtlOnDisable(&pVdma->CmdVbva);
+    if (pVdma->pCurRemainingHostCtl)
+    {
+        *pcbCtl = pVdma->pCurRemainingHostCtl->u.cmd.cbCmd;
+        return (VBOXCRCMDCTL*)pVdma->pCurRemainingHostCtl->u.cmd.pu8Cmd;
+    }
+
+    *pcbCtl = 0;
+    return NULL;
+}
+
+static int vboxVDMACrHgcmHandleEnable(struct VBOXVDMAHOST *pVdma)
+{
+    VBOXCRCMDCTL_ENABLE Enable;
+    Enable.Hdr.enmType = VBOXCRCMDCTL_TYPE_ENABLE;
+    Enable.hRHCmd = pVdma;
+    Enable.pfnRHCmd = vboxVDMACrHgcmHandleEnableRemainingHostCommand;
+
+    int rc = vboxVDMACrHgcmSubmitSync(pVdma, &Enable.Hdr, sizeof (Enable));
+    Assert(!pVdma->pCurRemainingHostCtl);
+    if (RT_SUCCESS(rc))
+    {
+        Assert(!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva));
+        return VINF_SUCCESS;
+    }
+
+    Assert(VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva));
+    WARN(("vboxVDMACrHgcmSubmitSync failed %d\n", rc));
+
+    return rc;
+}
+
+static int vdmaVBVAEnableProcess(struct VBOXVDMAHOST *pVdma, uint32_t u32Offset)
+{
+    if (VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
+    {
+        WARN(("vdma VBVA is already enabled\n"));
+        return VERR_INVALID_STATE;
+    }
+
+    VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost(pVdma->pHgsmi, u32Offset);
+    if (!pVBVA)
+    {
+        WARN(("invalid offset %d\n", u32Offset));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    if (!pVdma->CrSrvInfo.pfnEnable)
+    {
+#ifdef DEBUG_misha
+        WARN(("pfnEnable is NULL\n"));
+        return VERR_NOT_SUPPORTED;
+#endif
+    }
+
+    int rc = VBoxVBVAExHSEnable(&pVdma->CmdVbva, pVBVA);
+    if (RT_SUCCESS(rc))
+    {
+        VBOXCRCMDCTL Ctl;
+        Ctl.enmType = VBOXCRCMDCTL_TYPE_DISABLE;
+        rc = vboxVDMACrHgcmSubmitSync(pVdma, &Ctl, sizeof (Ctl));
+        if (RT_SUCCESS(rc))
+        {
+            PVGASTATE pVGAState = pVdma->pVGAState;
+            VBOXCRCMD_SVRENABLE_INFO Info;
+            Info.hCltScr = pVGAState->pDrv;
+            Info.pfnCltScrUpdateBegin = pVGAState->pDrv->pfnVBVAUpdateBegin;
+            Info.pfnCltScrUpdateProcess = pVGAState->pDrv->pfnVBVAUpdateProcess;
+            Info.pfnCltScrUpdateEnd = pVGAState->pDrv->pfnVBVAUpdateEnd;
+            rc = pVdma->CrSrvInfo.pfnEnable(pVdma->CrSrvInfo.hSvr, &Info);
+            if (RT_SUCCESS(rc))
+                return VINF_SUCCESS;
+            else
+                WARN(("pfnEnable failed %d\n", rc));
+
+            vboxVDMACrHgcmHandleEnable(pVdma);
+        }
+        else
+            WARN(("vboxVDMACrHgcmSubmitSync failed %d\n", rc));
+
+        VBoxVBVAExHSDisable(&pVdma->CmdVbva);
+    }
+    else
+        WARN(("VBoxVBVAExHSEnable failed %d\n", rc));
+
+    return rc;
+}
+
+static int vdmaVBVADisableProcess(struct VBOXVDMAHOST *pVdma)
+{
+    if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
+    {
+        Log(("vdma VBVA is already disabled\n"));
+        return VINF_SUCCESS;
+    }
+
+    int rc = pVdma->CrSrvInfo.pfnDisable(pVdma->CrSrvInfo.hSvr);
+    if (RT_SUCCESS(rc))
+    {
+        /* disable is a bit tricky
+         * we need to ensure the host ctl commands do not come out of order
+         * and do not come over HGCM channel until after it is enabled */
+        rc = vboxVDMACrHgcmHandleEnable(pVdma);
+        if (RT_SUCCESS(rc))
+            return rc;
+
+        PVGASTATE pVGAState = pVdma->pVGAState;
+        VBOXCRCMD_SVRENABLE_INFO Info;
+        Info.hCltScr = pVGAState->pDrv;
+        Info.pfnCltScrUpdateBegin = pVGAState->pDrv->pfnVBVAUpdateBegin;
+        Info.pfnCltScrUpdateProcess = pVGAState->pDrv->pfnVBVAUpdateProcess;
+        Info.pfnCltScrUpdateEnd = pVGAState->pDrv->pfnVBVAUpdateEnd;
+        pVdma->CrSrvInfo.pfnEnable(pVdma->CrSrvInfo.hSvr, &Info);
+    }
+    else
+        WARN(("pfnDisable failed %d\n", rc));
+
+    return rc;
+}
+
+static int vboxVDMACrHostCtlProcess(struct VBOXVDMAHOST *pVdma, VBVAEXHOSTCTL *pCmd)
+{
+    switch (pCmd->enmType)
+    {
+        case VBVAEXHOSTCTL_TYPE_HH_SAVESTATE:
+            if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
+            {
+                WARN(("VBVAEXHOSTCTL_TYPE_HH_SAVESTATE for disabled vdma VBVA\n"));
+                return VERR_INVALID_STATE;
+            }
+            return pVdma->CrSrvInfo.pfnSaveState(pVdma->CrSrvInfo.hSvr, pCmd->u.state.pSSM);
+        case VBVAEXHOSTCTL_TYPE_HH_LOADSTATE:
+            if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
+            {
+                WARN(("VBVAEXHOSTCTL_TYPE_HH_LOADSTATE for disabled vdma VBVA\n"));
+                return VERR_INVALID_STATE;
+            }
+            return pVdma->CrSrvInfo.pfnLoadState(pVdma->CrSrvInfo.hSvr, pCmd->u.state.pSSM, pCmd->u.state.u32Version);
+        case VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE:
+            if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
+            {
+                WARN(("VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE for disabled vdma VBVA\n"));
+                return VERR_INVALID_STATE;
+            }
+            return pVdma->CrSrvInfo.pfnHostCtl(pVdma->CrSrvInfo.hSvr, pCmd->u.cmd.pu8Cmd, pCmd->u.cmd.cbCmd);
+        case VBVAEXHOSTCTL_TYPE_HH_TERM:
+        {
+            int rc = vdmaVBVADisableProcess(pVdma);
+            if (!RT_SUCCESS(rc))
+            {
+                WARN(("vdmaVBVADisableProcess failed %d\n", rc));
+                return rc;
+            }
+
+            VBoxVDMAThreadMarkTerminating(&pVdma->Thread);
+            return VINF_SUCCESS;
+        }
+        case VBVAEXHOSTCTL_TYPE_HH_RESET:
+        {
+            int rc = vdmaVBVADisableProcess(pVdma);
+            if (!RT_SUCCESS(rc))
+            {
+                WARN(("vdmaVBVADisableProcess failed %d\n", rc));
+                return rc;
+            }
+            return VINF_SUCCESS;
+        }
+        default:
+            WARN(("unexpected host ctl type %d\n", pCmd->enmType));
+            return VERR_INVALID_PARAMETER;
+    }
+}
+
+static int vboxVDMACrGuestCtlProcess(struct VBOXVDMAHOST *pVdma, VBVAEXHOSTCTL *pCmd)
+{
+    switch (pCmd->enmType)
+    {
+       case VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE:
+           if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
+           {
+               WARN(("VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE for disabled vdma VBVA\n"));
+               return VERR_INVALID_STATE;
+           }
+           return pVdma->CrSrvInfo.pfnGuestCtl(pVdma->CrSrvInfo.hSvr, pCmd->u.cmd.pu8Cmd, pCmd->u.cmd.cbCmd);
+        case VBVAEXHOSTCTL_TYPE_GH_ENABLE_DISABLE:
+        {
+            VBVAENABLE *pEnable = (VBVAENABLE *)pCmd->u.cmd.pu8Cmd;
+            Assert(pCmd->u.cmd.cbCmd == sizeof (VBVAENABLE));
+            if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE)
+            {
+                uint32_t u32Offset = pEnable->u32Offset;
+                return vdmaVBVAEnableProcess(pVdma, u32Offset);
+            }
+
+            return vdmaVBVADisableProcess(pVdma);
+        }
+        default:
+            WARN(("unexpected ctl type %d\n", pCmd->enmType));
+            return VERR_INVALID_PARAMETER;
+    }
+}
+
 
 /*
@@ -280,5 +1162,5 @@
  *
  */
-static int vboxVDMACrCmdPreprocess(struct VBOXVDMAHOST *pVdma, uint8_t* pu8Cmd, uint32_t cbCmd)
+static int vboxVDMACrCmdProcess(struct VBOXVDMAHOST *pVdma, uint8_t* pu8Cmd, uint32_t cbCmd)
 {
     if (*pu8Cmd == VBOXCMDVBVA_OPTYPE_NOP)
@@ -305,87 +1187,65 @@
 }
 
-static DECLCALLBACK(int) vboxVDMACrCmdCltCmdGet(HVBOXCRCMDCLT hClt, PVBOXCMDVBVA_HDR *ppNextCmd, uint32_t *pcbNextCmd)
-{
-    struct VBOXVDMAHOST *pVdma = hClt;
-
-    VBoxVBVAExHPCmdCheckRelease(&pVdma->CmdVbva);
-
-    uint32_t cbCmd;
-    uint8_t *pu8Cmd;
-
-    for(;;)
-    {
-        int rc = VBoxVBVAExHPCmdGet(&pVdma->CmdVbva, &pu8Cmd, &cbCmd);
-        switch (rc)
-        {
-            case VINF_SUCCESS:
-            {
-                rc = vboxVDMACrCmdPreprocess(pVdma, pu8Cmd, cbCmd);
-                switch (rc)
-                {
-                    case VINF_SUCCESS:
-                        *ppNextCmd = (PVBOXCMDVBVA_HDR)pu8Cmd;
-                        *pcbNextCmd = cbCmd;
-                        return VINF_SUCCESS;
-                    case VINF_EOF:
-                        continue;
-                    default:
-                        Assert(!RT_FAILURE(rc));
-                        return RT_FAILURE(rc) ? rc : VERR_INTERNAL_ERROR;
-                }
-                break;
-            }
-            case VINF_EOF:
-                return VINF_EOF;
-            case VINF_PERMISSION_DENIED:
-                /* processing was paused, processing state was released, only VBoxVBVAExHS*** calls are now allowed */
-                return VINF_EOF;
-            case VINF_INTERRUPTED:
-                /* command processing was interrupted, processor state remains set. client can process any commands */
-                vboxVDMACrCmdNotifyPerform(pVdma);
-                return VINF_EOF;
-            default:
-                Assert(!RT_FAILURE(rc));
-                return RT_FAILURE(rc) ? rc : VERR_INTERNAL_ERROR;
-        }
-    }
-
-    WARN(("Warning: vboxVDMACrCmdCltCmdGet unexpected state\n"));
-    return VERR_INTERNAL_ERROR;
-}
-
-static DECLCALLBACK(int) vboxVDMACrCmdCltDmGet(HVBOXCRCMDCLT hClt, uint32_t idScreen, struct VBVAINFOSCREEN *pScreen, void **ppvVram)
-{
-    struct VBOXVDMAHOST *pVdma = hClt;
-    PVGASTATE pVGAState = pVdma->pVGAState;
-
-    return VBVAGetScreenInfo(pVGAState, idScreen, pScreen, ppvVram);
+static DECLCALLBACK(int) vboxVDMACrCmdEnable(HVBOXCRCMDSVR hSvr, VBOXCRCMD_SVRENABLE_INFO *pInfo)
+{
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(void) vboxVDMACrCmdDisable(HVBOXCRCMDSVR hSvr)
+{
+}
+
+static DECLCALLBACK(int) vboxVDMACrCmdCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
+{
+    return VERR_NOT_SUPPORTED;
+}
+
+static DECLCALLBACK(int) vboxVDMACrCmdCmd(HVBOXCRCMDSVR hSvr, PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd)
+{
+    switch (pCmd->u8OpCode)
+    {
+#if 0
+        case VBOXCMDVBVA_OPTYPE_BLT_OFFPRIMSZFMT_OR_ID:
+        {
+            crVBoxServerCrCmdBltProcess(pCmd, cbCmd);
+            break;
+        }
+#endif
+        default:
+            WARN(("unsupported command\n"));
+            pCmd->i8Result = -1;
+    }
+    return VINF_SUCCESS;
 }
 
 static int vboxVDMACrCtlHgsmiSetup(struct VBOXVDMAHOST *pVdma)
 {
-    PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pCmd;
-    pCmd = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP) vboxVDMACrCtlCreate (VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP,
-                                                                          sizeof (*pCmd));
+    PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pCmd = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)
+            vboxVDMACrCtlCreate (VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP, sizeof (*pCmd));
+    int rc = VERR_NO_MEMORY;
     if (pCmd)
     {
-        VBOXCRCMD_CLTINFO CltInfo;
-        CltInfo.hClient = pVdma;
-        CltInfo.pfnCmdGet = vboxVDMACrCmdCltCmdGet;
-        CltInfo.pfnDmGet = vboxVDMACrCmdCltDmGet;
         PVGASTATE pVGAState = pVdma->pVGAState;
         pCmd->pvVRamBase = pVGAState->vram_ptrR3;
         pCmd->cbVRam = pVGAState->vram_size;
-        pCmd->pCrCmdClientInfo = &CltInfo;
-        int rc = vboxVDMACrCtlPost(pVGAState, &pCmd->Hdr, sizeof (*pCmd));
-        Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
+        rc = vboxVDMACrCtlPost(pVGAState, &pCmd->Hdr, sizeof (*pCmd));
         if (RT_SUCCESS(rc))
         {
             rc = vboxVDMACrCtlGetRc(&pCmd->Hdr);
-        }
+            if (RT_SUCCESS(rc))
+                pVdma->CrSrvInfo = pCmd->CrCmdServerInfo;
+            else if (rc != VERR_NOT_SUPPORTED)
+                WARN(("vboxVDMACrCtlGetRc returned %d\n", rc));
+        }
+        else
+            WARN(("vboxVDMACrCtlPost failed %d\n", rc));
+
         vboxVDMACrCtlRelease(&pCmd->Hdr);
-        return rc;
-    }
-    return VERR_NO_MEMORY;
+    }
+
+    if (!RT_SUCCESS(rc))
+        memset(&pVdma->CrSrvInfo, 0, sizeof (pVdma->CrSrvInfo));
+
+    return rc;
 }
 
@@ -883,234 +1743,50 @@
 }
 
-#ifdef VBOX_VDMA_WITH_WORKERTHREAD
-
-int vboxVDMAPipeConstruct(PVBOXVDMAPIPE pPipe)
-{
-    int rc = RTSemEventCreate(&pPipe->hEvent);
-    AssertRC(rc);
-    if (RT_SUCCESS(rc))
-    {
-        rc = RTCritSectInit(&pPipe->hCritSect);
-        AssertRC(rc);
-        if (RT_SUCCESS(rc))
-        {
-            pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
-            pPipe->bNeedNotify = true;
-            return VINF_SUCCESS;
-//            RTCritSectDelete(pPipe->hCritSect);
-        }
-        RTSemEventDestroy(pPipe->hEvent);
-    }
-    return rc;
-}
-
-int vboxVDMAPipeOpenServer(PVBOXVDMAPIPE pPipe)
-{
-    int rc = RTCritSectEnter(&pPipe->hCritSect);
-    AssertRC(rc);
-    if (RT_SUCCESS(rc))
-    {
-        Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
-        switch (pPipe->enmState)
-        {
-            case VBOXVDMAPIPE_STATE_CREATED:
-                pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
-                pPipe->bNeedNotify = false;
-                rc = VINF_SUCCESS;
+static DECLCALLBACK(int) vboxVDMAWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
+{
+    PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvUser;
+    PVGASTATE pVGAState = pVdma->pVGAState;
+    VBVAEXHOSTCONTEXT *pCmdVbva = &pVdma->CmdVbva;
+    PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
+    uint8_t *pCmd;
+    uint32_t cbCmd;
+
+    int rc = VBoxVDMAThreadNotifyConstructSucceeded(&pVdma->Thread);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("VBoxVDMAThreadNotifyConstructSucceeded failed %d\n", rc));
+        return rc;
+    }
+
+    while (!VBoxVDMAThreadIsTerminating(&pVdma->Thread))
+    {
+        VBVAEXHOST_DATA_TYPE enmType = VBoxVBVAExHPDataGet(pCmdVbva, &pCmd, &cbCmd);
+        switch (enmType)
+        {
+            case VBVAEXHOST_DATA_TYPE_CMD:
+                vboxVDMACrCmdProcess(pVdma, pCmd, cbCmd);
+                VBoxVBVAExHPDataCompleteCmd(pCmdVbva, cbCmd);
+                VBVARaiseIrqNoWait(pVGAState, 0);
                 break;
-            case VBOXVDMAPIPE_STATE_OPENNED:
-                pPipe->bNeedNotify = false;
-                rc = VINF_ALREADY_INITIALIZED;
+            case VBVAEXHOST_DATA_TYPE_HOSTCTL:
+                rc = vboxVDMACrHostCtlProcess(pVdma, (VBVAEXHOSTCTL*)pCmd);
+                VBoxVBVAExHPDataCompleteCtl(pCmdVbva, (VBVAEXHOSTCTL*)pCmd, rc);
+                break;
+            case VBVAEXHOST_DATA_TYPE_GUESTCTL:
+                rc = vboxVDMACrGuestCtlProcess(pVdma, (VBVAEXHOSTCTL*)pCmd);
+                VBoxVBVAExHPDataCompleteCtl(pCmdVbva, (VBVAEXHOSTCTL*)pCmd, rc);
+                break;
+            case VBVAEXHOST_DATA_TYPE_NO_DATA:
+                rc = VBoxVDMAThreadEventWait(&pVdma->Thread, RT_INDEFINITE_WAIT);
+                AssertRC(rc);
                 break;
             default:
-                AssertBreakpoint();
-                rc = VERR_INVALID_STATE;
+                WARN(("unexpected type %d\n", enmType));
                 break;
         }
-
-        RTCritSectLeave(&pPipe->hCritSect);
-    }
-    return rc;
-}
-
-int vboxVDMAPipeCloseServer(PVBOXVDMAPIPE pPipe)
-{
-    int rc = RTCritSectEnter(&pPipe->hCritSect);
-    AssertRC(rc);
-    if (RT_SUCCESS(rc))
-    {
-        Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
-                || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
-        switch (pPipe->enmState)
-        {
-            case VBOXVDMAPIPE_STATE_CLOSING:
-                pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
-                rc = VINF_SUCCESS;
-                break;
-            case VBOXVDMAPIPE_STATE_CLOSED:
-                rc = VINF_ALREADY_INITIALIZED;
-                break;
-            default:
-                AssertBreakpoint();
-                rc = VERR_INVALID_STATE;
-                break;
-        }
-
-        RTCritSectLeave(&pPipe->hCritSect);
-    }
-    return rc;
-}
-
-int vboxVDMAPipeCloseClient(PVBOXVDMAPIPE pPipe)
-{
-    int rc = RTCritSectEnter(&pPipe->hCritSect);
-    AssertRC(rc);
-    if (RT_SUCCESS(rc))
-    {
-        bool bNeedNotify = false;
-        Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
-                || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
-                ||  pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
-        switch (pPipe->enmState)
-        {
-            case VBOXVDMAPIPE_STATE_OPENNED:
-                pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
-                bNeedNotify = pPipe->bNeedNotify;
-                pPipe->bNeedNotify = false;
-                break;
-            case VBOXVDMAPIPE_STATE_CREATED:
-                pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
-                pPipe->bNeedNotify = false;
-                break;
-            case VBOXVDMAPIPE_STATE_CLOSED:
-                rc = VINF_ALREADY_INITIALIZED;
-                break;
-            default:
-                AssertBreakpoint();
-                rc = VERR_INVALID_STATE;
-                break;
-        }
-
-        RTCritSectLeave(&pPipe->hCritSect);
-
-        if (bNeedNotify)
-        {
-            rc = RTSemEventSignal(pPipe->hEvent);
-            AssertRC(rc);
-        }
-    }
-    return rc;
-}
-
-
-typedef DECLCALLBACK(bool) FNHVBOXVDMARWCB(PVBOXVDMAPIPE pPipe, void *pvCallback);
-typedef FNHVBOXVDMARWCB *PFNHVBOXVDMARWCB;
-
-int vboxVDMAPipeModifyServer(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
-{
-    int rc = RTCritSectEnter(&pPipe->hCritSect);
-    AssertRC(rc);
-    if (RT_SUCCESS(rc))
-    {
-        do
-        {
-            Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
-                    || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
-
-            if (pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED)
-            {
-                bool bProcessing = pfnCallback(pPipe, pvCallback);
-                pPipe->bNeedNotify = !bProcessing;
-                if (bProcessing)
-                {
-                    RTCritSectLeave(&pPipe->hCritSect);
-                    rc = VINF_SUCCESS;
-                    break;
-                }
-                else if (pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING)
-                {
-                    pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
-                    RTCritSectLeave(&pPipe->hCritSect);
-                    rc = VINF_EOF;
-                    break;
-                }
-            }
-            else
-            {
-                AssertBreakpoint();
-                rc = VERR_INVALID_STATE;
-                RTCritSectLeave(&pPipe->hCritSect);
-                break;
-            }
-
-            RTCritSectLeave(&pPipe->hCritSect);
-
-            rc = RTSemEventWait(pPipe->hEvent, RT_INDEFINITE_WAIT);
-            AssertRC(rc);
-            if (!RT_SUCCESS(rc))
-                break;
-
-            rc = RTCritSectEnter(&pPipe->hCritSect);
-            AssertRC(rc);
-            if (!RT_SUCCESS(rc))
-                break;
-        } while (1);
-    }
-
-    return rc;
-}
-
-int vboxVDMAPipeModifyClient(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
-{
-    int rc = RTCritSectEnter(&pPipe->hCritSect);
-    AssertRC(rc);
-    if (RT_SUCCESS(rc))
-    {
-        bool bNeedNotify = false;
-        Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
-        if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
-        {
-            bool bModified = pfnCallback(pPipe, pvCallback);
-            if (bModified)
-            {
-                bNeedNotify = pPipe->bNeedNotify;
-                pPipe->bNeedNotify = false;
-            }
-        }
-        else
-            rc = VERR_INVALID_STATE;
-
-        RTCritSectLeave(&pPipe->hCritSect);
-
-        if (bNeedNotify)
-        {
-            rc = RTSemEventSignal(pPipe->hEvent);
-            AssertRC(rc);
-        }
-    }
-    return rc;
-}
-
-int vboxVDMAPipeDestruct(PVBOXVDMAPIPE pPipe)
-{
-    Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
-            || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
-    /* ensure the pipe is closed */
-    vboxVDMAPipeCloseClient(pPipe);
-
-    Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
-
-    if (pPipe->enmState != VBOXVDMAPIPE_STATE_CLOSED)
-        return VERR_INVALID_STATE;
-
-    int rc = RTCritSectDelete(&pPipe->hCritSect);
-    AssertRC(rc);
-
-    rc = RTSemEventDestroy(pPipe->hEvent);
-    AssertRC(rc);
+    }
 
     return VINF_SUCCESS;
 }
-#endif
 
 static void vboxVDMACommandProcess(PVBOXVDMAHOST pVdma, PVBOXVDMACBUF_DR pCmd, uint32_t cbCmd)
@@ -1180,85 +1856,4 @@
     AssertRC(rc);
 }
-
-#ifdef VBOX_VDMA_WITH_WORKERTHREAD
-typedef struct
-{
-    struct VBOXVDMAHOST *pVdma;
-    VBOXVDMAPIPE_CMD_BODY Cmd;
-    bool bHasCmd;
-} VBOXVDMACMD_PROCESS_CONTEXT, *PVBOXVDMACMD_PROCESS_CONTEXT;
-
-static DECLCALLBACK(bool) vboxVDMACommandProcessCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
-{
-    PVBOXVDMACMD_PROCESS_CONTEXT pContext = (PVBOXVDMACMD_PROCESS_CONTEXT)pvCallback;
-    struct VBOXVDMAHOST *pVdma = pContext->pVdma;
-    HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->PendingList);
-    if (pEntry)
-    {
-        PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
-        Assert(pPipeCmd);
-        pContext->Cmd = pPipeCmd->Cmd;
-        hgsmiListPrepend(&pVdma->CmdPool.List, pEntry);
-        pContext->bHasCmd = true;
-        return true;
-    }
-
-    pContext->bHasCmd = false;
-    return false;
-}
-
-static DECLCALLBACK(int) vboxVDMAWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
-{
-    PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvUser;
-    PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
-    VBOXVDMACMD_PROCESS_CONTEXT Context;
-    Context.pVdma = pVdma;
-
-    int rc = vboxVDMAPipeOpenServer(&pVdma->Pipe);
-    AssertRC(rc);
-    if (RT_SUCCESS(rc))
-    {
-        do
-        {
-            rc = vboxVDMAPipeModifyServer(&pVdma->Pipe, vboxVDMACommandProcessCb, &Context);
-            AssertRC(rc);
-            if (RT_SUCCESS(rc))
-            {
-                switch (Context.Cmd.enmType)
-                {
-                    case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
-                    {
-                        PVBOXVDMACBUF_DR pDr = Context.Cmd.u.pDr;
-                        vboxVDMACommandProcess(pVdma, pDr);
-                        break;
-                    }
-                    case VBOXVDMAPIPE_CMD_TYPE_DMACTL:
-                    {
-                        PVBOXVDMA_CTL pCtl = Context.Cmd.u.pCtl;
-                        vboxVDMAControlProcess(pVdma, pCtl);
-                        break;
-                    }
-                    default:
-                        AssertBreakpoint();
-                        break;
-                }
-
-                if (rc == VINF_EOF)
-                {
-                    rc = VINF_SUCCESS;
-                    break;
-                }
-            }
-            else
-                break;
-        } while (1);
-    }
-
-    /* always try to close the pipe to make sure the client side is notified */
-    int tmpRc = vboxVDMAPipeCloseServer(&pVdma->Pipe);
-    AssertRC(tmpRc);
-    return rc;
-}
-#endif
 
 #ifdef VBOX_VDMA_WITH_WATCHDOG
@@ -1301,39 +1896,25 @@
         AssertRC(rc);
 #endif
-#ifdef VBOX_VDMA_WITH_WORKERTHREAD
-        hgsmiListInit(&pVdma->PendingList);
-        rc = vboxVDMAPipeConstruct(&pVdma->Pipe);
-        AssertRC(rc);
+        rc = VBoxVBVAExHSInit(&pVdma->CmdVbva);
         if (RT_SUCCESS(rc))
         {
-            rc = RTThreadCreate(&pVdma->hWorkerThread, vboxVDMAWorkerThread, pVdma, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "VDMA");
-            AssertRC(rc);
+            rc = VBoxVDMAThreadCreate(&pVdma->Thread, vboxVDMAWorkerThread, pVdma);
             if (RT_SUCCESS(rc))
             {
-                hgsmiListInit(&pVdma->CmdPool.List);
-                pVdma->CmdPool.cCmds = cPipeElements;
-                for (uint32_t i = 0; i < cPipeElements; ++i)
-                {
-                    hgsmiListAppend(&pVdma->CmdPool.List, &pVdma->CmdPool.aCmds[i].Entry);
-                }
-# if 0 //def VBOX_WITH_CRHGSMI
-                int tmpRc = vboxVDMACrCtlHgsmiSetup(pVdma);
-# endif
-#endif
                 pVGAState->pVdma = pVdma;
-                VBoxVBVAExHSInit(&pVdma->CmdVbva);
 #ifdef VBOX_WITH_CRHGSMI
                 int rcIgnored = vboxVDMACrCtlHgsmiSetup(pVdma); NOREF(rcIgnored); /** @todo is this ignoring intentional? */
 #endif
                 return VINF_SUCCESS;
-#ifdef VBOX_VDMA_WITH_WORKERTHREAD
-            }
-
-            int tmpRc = vboxVDMAPipeDestruct(&pVdma->Pipe);
-            AssertRC(tmpRc);
-        }
+            }
+            else
+                WARN(("VBoxVDMAThreadCreate faile %d\n", rc));
+
+            VBoxVBVAExHSTerm(&pVdma->CmdVbva);
+        }
+        else
+            WARN(("VBoxVBVAExHSInit faile %d\n", rc));
 
         RTMemFree(pVdma);
-#endif
     }
     else
@@ -1343,44 +1924,32 @@
 }
 
+int vboxVDMAReset(struct VBOXVDMAHOST *pVdma)
+{
+    VBVAEXHOSTCTL Ctl;
+    Ctl.enmType = VBVAEXHOSTCTL_TYPE_HH_RESET;
+    int rc = vdmaVBVACtlSubmitSync(pVdma, &Ctl, VBVAEXHOSTCTL_SOURCE_HOST_ANY);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("vdmaVBVACtlSubmitSync failed %d\n", rc));
+        return rc;
+    }
+    return VINF_SUCCESS;
+}
+
 int vboxVDMADestruct(struct VBOXVDMAHOST *pVdma)
 {
-#ifdef VBOX_VDMA_WITH_WORKERTHREAD
-    /* @todo: implement*/
-    AssertBreakpoint();
-#endif
+    VBVAEXHOSTCTL Ctl;
+    Ctl.enmType = VBVAEXHOSTCTL_TYPE_HH_TERM;
+    int rc = vdmaVBVACtlSubmitSync(pVdma, &Ctl, VBVAEXHOSTCTL_SOURCE_HOST_ANY);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("vdmaVBVACtlSubmitSync failed %d\n", rc));
+        return rc;
+    }
+    VBoxVDMAThreadTerm(&pVdma->Thread);
     VBoxVBVAExHSTerm(&pVdma->CmdVbva);
     RTMemFree(pVdma);
     return VINF_SUCCESS;
 }
-
-#ifdef VBOX_VDMA_WITH_WORKERTHREAD
-typedef struct
-{
-    struct VBOXVDMAHOST *pVdma;
-    VBOXVDMAPIPE_CMD_BODY Cmd;
-    bool bQueued;
-} VBOXVDMACMD_SUBMIT_CONTEXT, *PVBOXVDMACMD_SUBMIT_CONTEXT;
-
-DECLCALLBACK(bool) vboxVDMACommandSubmitCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
-{
-    PVBOXVDMACMD_SUBMIT_CONTEXT pContext = (PVBOXVDMACMD_SUBMIT_CONTEXT)pvCallback;
-    struct VBOXVDMAHOST *pVdma = pContext->pVdma;
-    HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->CmdPool.List);
-    Assert(pEntry);
-    if (pEntry)
-    {
-        PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
-        pPipeCmd->Cmd = pContext->Cmd;
-        VBoxSHGSMICommandMarkAsynchCompletion(pContext->Cmd.u.pvCmd);
-        pContext->bQueued = true;
-        hgsmiListAppend(&pVdma->PendingList, pEntry);
-        return true;
-    }
-
-    /* @todo: should we try to flush some commands here? */
-    pContext->bQueued = false;
-    return false;
-}
-#endif
 
 int vboxVDMASaveStateExecPrep(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
@@ -1545,375 +2114,199 @@
 
 /**/
-static int vboxVBVAExHSProcessorAcquire(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    Assert(pCmdVbva->u32State != VBVAEXHOSTCONTEXT_STATE_STOPPED);
-
-    uint32_t oldState;
-    if (!ASMAtomicReadU32(&pCmdVbva->u32Pause))
-    {
-        if (ASMAtomicCmpXchgExU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_PROCESSING, VBVAEXHOSTCONTEXT_STATE_LISTENING, &oldState))
-            return VINF_SUCCESS;
-        return oldState == VBVAEXHOSTCONTEXT_STATE_PROCESSING ? VERR_SEM_BUSY : VERR_INVALID_STATE;
-    }
-    return VERR_INVALID_STATE;
-}
-
-static bool vboxVBVAExHPCheckPause(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
-
-    if (!ASMAtomicReadU32(&pCmdVbva->u32Pause))
-        return false;
-
-    ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_PAUSED);
-    return true;
-}
-
-static bool vboxVBVAExHPCheckOtherCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
-
-    return !!ASMAtomicUoReadU32(&pCmdVbva->u32cOtherCommands);
-}
-
-static void vboxVBVAExHPProcessorRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
-
-    if (!vboxVBVAExHPCheckPause(pCmdVbva))
-        ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_LISTENING);
+
+static int vdmaVBVACtlSubmit(PVBOXVDMAHOST pVdma, VBVAEXHOSTCTL* pCtl, VBVAEXHOSTCTL_SOURCE enmSource, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
+{
+    int rc = VBoxVBVAExHCtlSubmit(&pVdma->CmdVbva, pCtl, enmSource, pfnComplete, pvComplete);
+    if (RT_SUCCESS(rc))
+    {
+        if (rc == VINF_SUCCESS)
+            return VBoxVDMAThreadEventNotify(&pVdma->Thread);
+        else
+            Assert(rc == VINF_ALREADY_INITIALIZED);
+    }
     else
-        ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_PAUSED);
-}
-
-static void vboxVBVAExHPHgEventSet(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
-
-    ASMAtomicOrU32(&pCmdVbva->pVBVA->hostFlags.u32HostEvents, VBVA_F_STATE_PROCESSING);
-}
-
-static void vboxVBVAExHPHgEventClear(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
-
-    ASMAtomicAndU32(&pCmdVbva->pVBVA->hostFlags.u32HostEvents, ~VBVA_F_STATE_PROCESSING);
-}
-
-static bool vboxVBVAExHPCmdCheckRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    if (!pCmdVbva->cbCurData)
-        return false;
-
-    VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
-    pVBVA->off32Data = (pVBVA->off32Data + pCmdVbva->cbCurData) % pVBVA->cbData;
-
-    pVBVA->indexRecordFirst = (pVBVA->indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
-
-    pCmdVbva->cbCurData = 0;
-
-    return true;
-}
-
-static int vboxVBVAExHPCmdGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
-{
-    Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
-
-    VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
-
-    uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
-    uint32_t indexRecordFree = pVBVA->indexRecordFree;
-
-    Log(("first = %d, free = %d\n",
-                   indexRecordFirst, indexRecordFree));
-
-    if (indexRecordFirst == indexRecordFree)
-    {
-        /* No records to process. Return without assigning output variables. */
-        return VINF_EOF;
-    }
-
-    uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVBVA->aRecords[indexRecordFirst].cbRecord);
-
-    /* A new record need to be processed. */
-    if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
-    {
-        /* the record is being recorded, try again */
-        return VINF_TRY_AGAIN;
-    }
-
-    uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
-
-    if (!cbRecord)
-    {
-        /* the record is being recorded, try again */
-        return VINF_TRY_AGAIN;
-    }
-
-    /* we should not get partial commands here actually */
-    Assert(cbRecord);
-
-    /* The size of largest contiguous chunk in the ring biffer. */
-    uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
-
-    /* The pointer to data in the ring buffer. */
-    uint8_t *pSrc = &pVBVA->au8Data[pVBVA->off32Data];
-
-    /* Fetch or point the data. */
-    if (u32BytesTillBoundary >= cbRecord)
-    {
-        /* The command does not cross buffer boundary. Return address in the buffer. */
-        *ppCmd = pSrc;
-        *pcbCmd = cbRecord;
-        pCmdVbva->cbCurData = cbRecord;
+        WARN(("VBoxVBVAExHCtlSubmit failed %d\n", rc));
+
+    return rc;
+}
+
+static DECLCALLBACK(void) vboxCmdVBVACmdCtlGuestCompletion(VBVAEXHOSTCONTEXT *pVbva, struct VBVAEXHOSTCTL *pCtl, int rc, void *pvContext)
+{
+    PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvContext;
+    VBOXCMDVBVA_CTL *pGCtl = (VBOXCMDVBVA_CTL*)(pCtl->u.cmd.pu8Cmd - sizeof (VBOXCMDVBVA_CTL));
+    AssertRC(rc);
+    pGCtl->i32Result = rc;
+
+    Assert(pVdma->pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD);
+    rc = VBoxSHGSMICommandComplete(pVdma->pHgsmi, pGCtl);
+    AssertRC(rc);
+
+    VBoxVBVAExHCtlFree(pVbva, pCtl);
+}
+
+static int vdmaVBVACtlOpaqueSubmit(PVBOXVDMAHOST pVdma, VBVAEXHOSTCTL_SOURCE enmSource, uint8_t* pu8Cmd, uint32_t cbCmd, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
+{
+    VBVAEXHOSTCTL* pHCtl = VBoxVBVAExHCtlCreate(&pVdma->CmdVbva, VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE);
+    if (!pHCtl)
+    {
+        WARN(("VBoxVBVAExHCtlCreate failed\n"));
+        return VERR_NO_MEMORY;
+    }
+
+    pHCtl->u.cmd.pu8Cmd = pu8Cmd;
+    pHCtl->u.cmd.cbCmd = cbCmd;
+    int rc = vdmaVBVACtlSubmit(pVdma, pHCtl, enmSource, pfnComplete, pvComplete);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("vdmaVBVACtlSubmit failed rc %d\n", rc));
+        return rc;;
+    }
+    return VINF_SUCCESS;
+}
+
+static int vdmaVBVACtlOpaqueGuestSubmit(PVBOXVDMAHOST pVdma, VBOXCMDVBVA_CTL *pCtl, uint32_t cbCtl)
+{
+    Assert(cbCtl >= sizeof (VBOXCMDVBVA_CTL));
+    VBoxSHGSMICommandMarkAsynchCompletion(pCtl);
+    int rc = vdmaVBVACtlOpaqueSubmit(pVdma, VBVAEXHOSTCTL_SOURCE_GUEST, (uint8_t*)(pCtl+1), cbCtl - sizeof (VBOXCMDVBVA_CTL), vboxCmdVBVACmdCtlGuestCompletion, pVdma);
+    if (RT_SUCCESS(rc))
         return VINF_SUCCESS;
-    }
-
-    LogRel(("CmdVbva: cross-bound writes unsupported\n"));
-    return VERR_INVALID_STATE;
-}
-
-/* Resumes command processing
- * @returns - same as VBoxVBVAExHSCheckCommands
- */
-static int vboxVBVAExHSResume(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    Assert(pCmdVbva->u32State != VBVAEXHOSTCONTEXT_STATE_STOPPED);
-
-    ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_LISTENING);
-
-    return VBoxVBVAExHSCheckCommands(pCmdVbva);
-}
-
-/* pause the command processing. this will make the processor stop the command processing and release the processing state
- * to resume the command processing the vboxVBVAExHSResume must be called */
-static void vboxVBVAExHSPause(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    Assert(pCmdVbva->u32State != VBVAEXHOSTCONTEXT_STATE_STOPPED);
-
-    Assert(!pCmdVbva->u32Pause);
-
-    ASMAtomicWriteU32(&pCmdVbva->u32Pause, 1);
-
-    for(;;)
-    {
-        if (ASMAtomicCmpXchgU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_PAUSED, VBVAEXHOSTCONTEXT_STATE_LISTENING))
-            break;
-
-        if (ASMAtomicReadU32(&pCmdVbva->u32State) == VBVAEXHOSTCONTEXT_STATE_PAUSED)
-            break;
-
-        RTThreadSleep(2);
-    }
-
-    pCmdVbva->u32Pause = 0;
-}
-
-/* releases (completed) the command previously acquired by VBoxVBVAExHCmdGet
- * for convenience can be called if no command is currently acquired
- * in that case it will do nothing and return false.
- * if the completion notification is needed returns true. */
-static bool VBoxVBVAExHPCmdCheckRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
-
-    return vboxVBVAExHPCmdCheckRelease(pCmdVbva);
-}
-
-/*
- * @returns
- *  VINF_SUCCESS - new command is obtained
- *  VINF_EOF - processor has completed all commands and release the processing state, only VBoxVBVAExHS*** calls are now allowed
- *  VINF_PERMISSION_DENIED - processing was paused, processing state was released, only VBoxVBVAExHS*** calls are now allowed
- *  VINF_INTERRUPTED - command processing was interrupted, processor state remains set. client can process any commands,
- *                     and call VBoxVBVAExHPCmdGet again for further processing
- *  VERR_** - error happened, most likely guest corrupted VBVA data
- *
- */
-static int VBoxVBVAExHPCmdGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
-{
-    Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
-
-    for(;;)
-    {
-        if (vboxVBVAExHPCheckPause(pCmdVbva))
-            return VINF_PERMISSION_DENIED;
-        if (vboxVBVAExHPCheckOtherCommands(pCmdVbva))
-            return VINF_INTERRUPTED;
-
-        int rc = vboxVBVAExHPCmdGet(pCmdVbva, ppCmd, pcbCmd);
-        switch (rc)
-        {
-            case VINF_SUCCESS:
-                return VINF_SUCCESS;
-            case VINF_EOF:
-                vboxVBVAExHPHgEventClear(pCmdVbva);
-                vboxVBVAExHPProcessorRelease(pCmdVbva);
-                /* we need to prevent racing between us clearing the flag and command check/submission thread, i.e.
-                 * 1. we check the queue -> and it is empty
-                 * 2. submitter adds command to the queue
-                 * 3. submitter checks the "processing" -> and it is true , thus it does not submit a notification
-                 * 4. we clear the "processing" state
-                 * 5. ->here we need to re-check the queue state to ensure we do not leak the notification of the above command
-                 * 6. if the queue appears to be not-empty set the "processing" state back to "true"
-                 **/
-                if (VBoxVBVAExHSCheckCommands(pCmdVbva) == VINF_SUCCESS)
-                    continue;
-                return VINF_EOF;
-            case VINF_TRY_AGAIN:
-                RTThreadSleep(1);
-                continue;
-            default:
-                /* this is something really unexpected, i.e. most likely guest has written something incorrect to the VBVA buffer */
-                if (RT_FAILURE(rc))
-                    return rc;
-
-                WARN(("Warning: vboxVBVAExHCmdGet returned unexpected success status %d\n", rc));
-                return VERR_INTERNAL_ERROR;
-        }
-    }
-
-    WARN(("Warning: VBoxVBVAExHCmdGet unexpected state\n"));
-    return VERR_INTERNAL_ERROR;
-}
-
-/* Checks whether the new commands are ready for processing
- * @returns
- *   VINF_SUCCESS - there are commands are in a queue, and the given thread is now the processor (i.e. typically it would delegate processing to a worker thread)
- *   VINF_EOF - no commands in a queue
- *   VINF_ALREADY_INITIALIZED - another thread already processing the commands
- *   VERR_INVALID_STATE - the VBVA is paused or pausing */
-static int VBoxVBVAExHSCheckCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    if (ASMAtomicUoReadU32(&pCmdVbva->u32State) == VBVAEXHOSTCONTEXT_STATE_STOPPED)
-        return VINF_EOF;
-
-    int rc = vboxVBVAExHSProcessorAcquire(pCmdVbva);
+
+    WARN(("vdmaVBVACtlOpaqueSubmit failed %d\n", rc));
+    pCtl->i32Result = rc;
+    rc = VBoxSHGSMICommandComplete(pVdma->pHgsmi, pCtl);
+    AssertRC(rc);
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(void) vboxCmdVBVACmdCtlHostCompletion(VBVAEXHOSTCONTEXT *pVbva, struct VBVAEXHOSTCTL *pCtl, int rc, void *pvCompletion)
+{
+    VBOXCRCMDCTL* pVboxCtl = (VBOXCRCMDCTL*)pCtl->u.cmd.pu8Cmd;
+    if (pVboxCtl->pfnInternal)
+        ((PFNCRCTLCOMPLETION)pVboxCtl->pfnInternal)(pVboxCtl, pCtl->u.cmd.cbCmd, rc, pvCompletion);
+    VBoxVBVAExHCtlFree(pVbva, pCtl);
+}
+
+static int vdmaVBVACtlOpaqueHostSubmit(PVBOXVDMAHOST pVdma, struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
+        PFNCRCTLCOMPLETION pfnCompletion,
+        void *pvCompletion)
+{
+    pCmd->pfnInternal = (void(*)())pfnCompletion;
+    int rc = vdmaVBVACtlOpaqueSubmit(pVdma, VBVAEXHOSTCTL_SOURCE_HOST_ENABLED, (uint8_t*)pCmd, cbCmd, vboxCmdVBVACmdCtlHostCompletion, pvCompletion);
+    if (!RT_SUCCESS(rc))
+    {
+        if (rc == VERR_INVALID_STATE)
+        {
+            pCmd->pfnInternal = NULL;
+            PVGASTATE pVGAState = pVdma->pVGAState;
+            rc = pVGAState->pDrv->pfnCrHgcmCtlSubmit(pVGAState->pDrv, pCmd, cbCmd, pfnCompletion, pvCompletion);
+            if (!RT_SUCCESS(rc))
+                WARN(("pfnCrHgsmiControlProcess failed %d\n", rc));
+
+            return rc;
+        }
+        WARN(("vdmaVBVACtlOpaqueSubmit failed %d\n", rc));
+        return rc;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static int vdmaVBVACtlEnableDisableSubmitInternal(PVBOXVDMAHOST pVdma, VBOXCMDVBVA_CTL_ENABLE *pEnable, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
+{
+    VBVAEXHOSTCTL* pHCtl = VBoxVBVAExHCtlCreate(&pVdma->CmdVbva, VBVAEXHOSTCTL_TYPE_GH_ENABLE_DISABLE);
+    if (!pHCtl)
+    {
+        WARN(("VBoxVBVAExHCtlCreate failed\n"));
+        return VERR_NO_MEMORY;
+    }
+
+    pHCtl->u.cmd.pu8Cmd = (uint8_t*)&pEnable->Enable;
+    pHCtl->u.cmd.cbCmd = sizeof (pEnable->Enable);
+    int rc = vdmaVBVACtlSubmit(pVdma, pHCtl, VBVAEXHOSTCTL_SOURCE_GUEST, pfnComplete, pvComplete);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("vdmaVBVACtlSubmit failed rc %d\n", rc));
+        return rc;;
+    }
+    return VINF_SUCCESS;
+}
+
+static int vdmaVBVACtlEnableDisableSubmit(PVBOXVDMAHOST pVdma, VBOXCMDVBVA_CTL_ENABLE *pEnable)
+{
+    VBoxSHGSMICommandMarkAsynchCompletion(&pEnable->Hdr);
+    int rc = vdmaVBVACtlEnableDisableSubmitInternal(pVdma, pEnable, vboxCmdVBVACmdCtlGuestCompletion, pVdma);
     if (RT_SUCCESS(rc))
-    {
-        /* we are the processor now */
-        VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
-
-        uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
-        uint32_t indexRecordFree = pVBVA->indexRecordFree;
-
-        if (indexRecordFirst != indexRecordFree)
-        {
-            vboxVBVAExHPHgEventSet(pCmdVbva);
-            return VINF_SUCCESS;
-        }
-
-        vboxVBVAExHPProcessorRelease(pCmdVbva);
-        return VINF_EOF;
-    }
-    if (rc == VERR_SEM_BUSY)
-        return VINF_ALREADY_INITIALIZED;
-    Assert(rc == VERR_INVALID_STATE);
-    return VERR_INVALID_STATE;
-}
-
-static void VBoxVBVAExHSInit(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    memset(pCmdVbva, 0, sizeof (*pCmdVbva));
-}
-
-static int VBoxVBVAExHSEnable(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVABUFFER *pVBVA)
-{
-    if (ASMAtomicUoReadU32(&pCmdVbva->u32State) != VBVAEXHOSTCONTEXT_STATE_STOPPED)
-        return VINF_ALREADY_INITIALIZED;
-
-    pCmdVbva->pVBVA = pVBVA;
-    pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
-    ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_LISTENING);
+        return VINF_SUCCESS;
+
+    WARN(("vdmaVBVACtlEnableDisableSubmitInternal failed %d\n", rc));
+    pEnable->Hdr.i32Result = rc;
+    rc = VBoxSHGSMICommandComplete(pVdma->pHgsmi, &pEnable->Hdr);
+    AssertRC(rc);
     return VINF_SUCCESS;
 }
 
-static int VBoxVBVAExHSDisable(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    if (ASMAtomicUoReadU32(&pCmdVbva->u32State) == VBVAEXHOSTCONTEXT_STATE_STOPPED)
-        return VINF_SUCCESS;
-
-    /* ensure no commands pending and one tries to submit them */
-    int rc = vboxVBVAExHSProcessorAcquire(pCmdVbva);
+static DECLCALLBACK(void) vdmaVBVACtlSubmitSyncCompletion(VBVAEXHOSTCONTEXT *pVbva, struct VBVAEXHOSTCTL *pCtl, int rc, void *pvContext)
+{
+    VDMA_VBVA_CTL_CYNC_COMPLETION *pData = (VDMA_VBVA_CTL_CYNC_COMPLETION*)pvContext;
+    pData->rc = rc;
+    rc = RTSemEventSignal(pData->hEvent);
+    if (!RT_SUCCESS(rc))
+        WARN(("RTSemEventSignal failed %d\n", rc));
+}
+
+static int vdmaVBVACtlSubmitSync(PVBOXVDMAHOST pVdma, VBVAEXHOSTCTL* pCtl, VBVAEXHOSTCTL_SOURCE enmSource)
+{
+    VDMA_VBVA_CTL_CYNC_COMPLETION Data;
+    Data.rc = VERR_NOT_IMPLEMENTED;
+    int rc = RTSemEventCreate(&Data.hEvent);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("RTSemEventCreate failed %d\n", rc));
+        return rc;
+    }
+
+    rc = vdmaVBVACtlSubmit(pVdma, pCtl, enmSource, vdmaVBVACtlSubmitSyncCompletion, &Data);
     if (RT_SUCCESS(rc))
     {
-        pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
-        memset(pCmdVbva, 0, sizeof (*pCmdVbva));
-        return VINF_SUCCESS;
-    }
-    return VERR_INVALID_STATE;
-}
-
-static void VBoxVBVAExHSTerm(struct VBVAEXHOSTCONTEXT *pCmdVbva)
-{
-    /* ensure the processor is stopped */
-    if (ASMAtomicUoReadU32(&pCmdVbva->u32State) == VBVAEXHOSTCONTEXT_STATE_STOPPED)
-        return;
-
-    /* ensure no one tries to submit the command */
-    vboxVBVAExHSPause(pCmdVbva);
-    pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
-    memset(pCmdVbva, 0, sizeof (*pCmdVbva));
-}
-
-/* Saves state
- * @returns - same as VBoxVBVAExHSCheckCommands, or failure on load state fail
- */
-static int VBoxVBVAExHSSaveState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM)
-{
-    int rc;
-    if (ASMAtomicUoReadU32(&pCmdVbva->u32State) != VBVAEXHOSTCONTEXT_STATE_STOPPED)
-    {
-        vboxVBVAExHSPause(pCmdVbva);
-        rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pCmdVbva->pVBVA) - pu8VramBase));
-        AssertRCReturn(rc, rc);
-        return vboxVBVAExHSResume(pCmdVbva);
-    }
-
-    rc = SSMR3PutU32(pSSM, 0xffffffff);
-    AssertRCReturn(rc, rc);
-
-    return VINF_EOF;
-}
-
-/* Loads state
- * @returns - same as VBoxVBVAExHSCheckCommands, or failure on load state fail
- */
-static int VBoxVBVAExHSLoadState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM, uint32_t u32Version)
-{
-    uint32_t u32;
-    int rc = SSMR3GetU32(pSSM, &u32);
-    AssertRCReturn(rc, rc);
-    if (u32 != 0xffffffff)
-    {
-        VBVABUFFER *pVBVA = (VBVABUFFER*)pu8VramBase + u32;
-        rc = VBoxVBVAExHSEnable(pCmdVbva, pVBVA);
-        AssertRCReturn(rc, rc);
-        return VBoxVBVAExHSCheckCommands(pCmdVbva);
-    }
-
-    return VINF_EOF;
-}
-
-int vboxCmdVBVAEnable(PVGASTATE pVGAState, VBVABUFFER *pVBVA)
-{
-    struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
-    return VBoxVBVAExHSEnable(&pVdma->CmdVbva, pVBVA);
-}
-
-int vboxCmdVBVADisable(PVGASTATE pVGAState)
-{
-    struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
-    return VBoxVBVAExHSDisable(&pVdma->CmdVbva);
-}
-
-static int vboxCmdVBVACmdSubmitPerform(PVGASTATE pVGAState)
-{
-    struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
+        rc = RTSemEventWait(Data.hEvent, RT_INDEFINITE_WAIT);
+        if (RT_SUCCESS(rc))
+        {
+            rc = Data.rc;
+            if (!RT_SUCCESS(rc))
+                WARN(("vdmaVBVACtlSubmitSyncCompletion returned %d\n", rc));
+        }
+        else
+            WARN(("RTSemEventWait failed %d\n", rc));
+    }
+    else
+        WARN(("vdmaVBVACtlSubmit failed %d\n", rc));
+
+    RTSemEventDestroy(Data.hEvent);
+
+    return rc;
+}
+
+static int vdmaVBVAPause(PVBOXVDMAHOST pVdma)
+{
+    VBVAEXHOSTCTL Ctl;
+    Ctl.enmType = VBVAEXHOSTCTL_TYPE_HH_INTERNAL_PAUSE;
+    return vdmaVBVACtlSubmitSync(pVdma, &Ctl, VBVAEXHOSTCTL_SOURCE_HOST_ANY);
+}
+
+static int vdmaVBVAResume(PVBOXVDMAHOST pVdma)
+{
+    VBVAEXHOSTCTL Ctl;
+    Ctl.enmType = VBVAEXHOSTCTL_TYPE_HH_INTERNAL_RESUME;
+    return vdmaVBVACtlSubmitSync(pVdma, &Ctl, VBVAEXHOSTCTL_SOURCE_HOST_ANY);
+}
+
+static int vboxVDMACmdSubmitPerform(struct VBOXVDMAHOST *pVdma)
+{
     int rc = VBoxVBVAExHSCheckCommands(&pVdma->CmdVbva);
     switch (rc)
     {
         case VINF_SUCCESS:
-            return pVGAState->pDrv->pfnCrCmdNotifyCmds(pVGAState->pDrv);
+            return VBoxVDMAThreadEventNotify(&pVdma->Thread);
         case VINF_ALREADY_INITIALIZED:
         case VINF_EOF:
@@ -1926,16 +2319,69 @@
 }
 
+
+int vboxCmdVBVACmdHostCtl(PPDMIDISPLAYVBVACALLBACKS pInterface,
+                                                               struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
+                                                               PFNCRCTLCOMPLETION pfnCompletion,
+                                                               void *pvCompletion)
+{
+    PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
+    struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
+    return vdmaVBVACtlOpaqueHostSubmit(pVdma, pCmd, cbCmd, pfnCompletion, pvCompletion);
+}
+
+int vboxCmdVBVACmdCtl(PVGASTATE pVGAState, VBOXCMDVBVA_CTL *pCtl, uint32_t cbCtl)
+{
+    struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
+    int rc = VINF_SUCCESS;
+    switch (pCtl->u32Type)
+    {
+        case VBOXCMDVBVACTL_TYPE_3DCTL:
+            return vdmaVBVACtlOpaqueGuestSubmit(pVdma, pCtl, cbCtl);
+        case VBOXCMDVBVACTL_TYPE_ENABLE:
+            if (cbCtl != sizeof (VBOXCMDVBVA_CTL_ENABLE))
+            {
+                WARN(("incorrect enable size\n"));
+                rc = VERR_INVALID_PARAMETER;
+                break;
+            }
+            return vdmaVBVACtlEnableDisableSubmit(pVdma, (VBOXCMDVBVA_CTL_ENABLE*)pCtl);
+        default:
+            WARN(("unsupported type\n"));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+    }
+
+    pCtl->i32Result = rc;
+    rc = VBoxSHGSMICommandComplete(pVdma->pHgsmi, pCtl);
+    AssertRC(rc);
+    return VINF_SUCCESS;
+}
+
 int vboxCmdVBVACmdSubmit(PVGASTATE pVGAState)
 {
-    return vboxCmdVBVACmdSubmitPerform(pVGAState);
+    if (!VBoxVBVAExHSIsEnabled(&pVGAState->pVdma->CmdVbva))
+    {
+        WARN(("vdma VBVA is disabled\n"));
+        return VERR_INVALID_STATE;
+    }
+
+    return vboxVDMACmdSubmitPerform(pVGAState->pVdma);
 }
 
 int vboxCmdVBVACmdFlush(PVGASTATE pVGAState)
 {
-    return vboxCmdVBVACmdSubmitPerform(pVGAState);
+    WARN(("flush\n"));
+    if (!VBoxVBVAExHSIsEnabled(&pVGAState->pVdma->CmdVbva))
+    {
+        WARN(("vdma VBVA is disabled\n"));
+        return VERR_INVALID_STATE;
+    }
+    return vboxVDMACmdSubmitPerform(pVGAState->pVdma);
 }
 
 void vboxCmdVBVACmdTimer(PVGASTATE pVGAState)
 {
-    vboxCmdVBVACmdSubmitPerform(pVGAState);
-}
+    if (!VBoxVBVAExHSIsEnabled(&pVGAState->pVdma->CmdVbva))
+        return;
+    vboxVDMACmdSubmitPerform(pVGAState->pVdma);
+}
Index: /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h	(revision 50753)
+++ /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h	(revision 50754)
@@ -34,4 +34,5 @@
 #include <VBox/Hardware/VBoxVideoVBE.h>
 #include <VBox/VBoxVideo3D.h>
+#include <VBox/VBoxVideoHost3D.h>
 
 #ifdef __cplusplus
@@ -406,6 +407,4 @@
     uint32_t fBlitterMode;
     CR_BLITTER Blitter;
-
-    VBOXCRCMD_CLTINFO CltInfo;
 
     CR_SERVER_RPW RpwWorker;
@@ -486,4 +485,6 @@
     SPUDispatchTable TmpCtxDispatch;
 
+    VBOXCRCMD_SVRENABLE_INFO CrCmdClientInfo;
+
 #ifdef VBOX_WITH_CRSERVER_DUMPER
     CR_RECORDER Recorder;
@@ -566,5 +567,4 @@
 extern DECLEXPORT(int32_t) crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl);
 
-extern DECLEXPORT(int32_t) crVBoxServerCrCmdNotifyCmds();
 #endif
 
Index: /trunk/src/VBox/GuestHost/OpenGL/include/cr_vreg.h
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/include/cr_vreg.h	(revision 50753)
+++ /trunk/src/VBox/GuestHost/OpenGL/include/cr_vreg.h	(revision 50754)
@@ -64,4 +64,18 @@
     VBoxRectScale(pResult, xScale, yScale);
 }
+
+DECLINLINE(void) VBoxRectUnscale(PRTRECT pRect, float xScale, float yScale)
+{
+    pRect->xLeft = CR_FLOAT_RCAST(int32_t, pRect->xLeft / xScale);
+    pRect->yTop = CR_FLOAT_RCAST(int32_t, pRect->yTop / yScale);
+    pRect->xRight = CR_FLOAT_RCAST(int32_t, pRect->xRight / xScale);
+    pRect->yBottom = CR_FLOAT_RCAST(int32_t, pRect->yBottom / yScale);
+}
+
+DECLINLINE(void) VBoxRectUnscaled(const RTRECT *pRect, float xScale, float yScale, PRTRECT pResult)
+{
+    *pResult = *pRect;
+    VBoxRectUnscale(pResult, xScale, yScale);
+}
 #endif
 
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp	(revision 50753)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp	(revision 50754)
@@ -962,5 +962,5 @@
  * We differentiate between a function handler for the guest and one for the host.
  */
-static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+static int svcHostCallPerform(void *, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
 {
     int rc = VINF_SUCCESS;
@@ -980,8 +980,4 @@
     switch (u32Function)
     {
-        case SHCRGL_HOST_FN_CRCMD_NOTIFY_CMDS:
-        {
-            rc = crVBoxServerCrCmdNotifyCmds();
-        } break;
 #ifdef VBOX_WITH_CRHGSMI
         case SHCRGL_HOST_FN_CRHGSMI_CMD:
@@ -1477,4 +1473,50 @@
 }
 
+static DECLCALLBACK(int) svcHostCall (void *, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+    switch (u32Function)
+    {
+        case SHCRGL_HOST_FN_CTL:
+        {
+            if (cParms != 1)
+            {
+                WARN(("cParams != 1"));
+                return VERR_INVALID_PARAMETER;
+            }
+
+            if (paParms->type != VBOX_HGCM_SVC_PARM_PTR)
+            {
+                WARN(("invalid param type"));
+                return VERR_INVALID_PARAMETER;
+            }
+
+            if (paParms->u.pointer.size < sizeof (VBOXCRCMDCTL))
+            {
+                WARN(("invalid param size"));
+                return VERR_INVALID_PARAMETER;
+            }
+
+            if ((paParms->u.pointer.size - sizeof (VBOXCRCMDCTL)) % sizeof(VBOXHGCMSVCPARM))
+            {
+                WARN(("invalid param size"));
+                return VERR_INVALID_PARAMETER;
+            }
+
+            VBOXCRCMDCTL *pCtl = (VBOXCRCMDCTL*)paParms->u.pointer.addr;
+            uint32_t cParams = (paParms->u.pointer.size - sizeof (VBOXCRCMDCTL)) / sizeof (VBOXHGCMSVCPARM);
+            return svcHostCallPerform(NULL, pCtl->u32Function, cParms, (VBOXHGCMSVCPARM*)(pCtl + 1));
+        }
+        case VBOXCRCMDCTL_TYPE_DISABLE:
+            AssertMsgFailed(("VBOXCRCMDCTL_TYPE_DISABLE\n"));
+            return VERR_NOT_IMPLEMENTED;
+        case VBOXCRCMDCTL_TYPE_ENABLE:
+            AssertMsgFailed(("VBOXCRCMDCTL_TYPE_ENABLE\n"));
+            return VERR_NOT_IMPLEMENTED;
+        default:
+            return svcHostCallPerform(NULL, u32Function, cParms, paParms);
+    }
+
+}
+
 extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable)
 {
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h	(revision 50753)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h	(revision 50754)
@@ -428,5 +428,5 @@
 void CrFbVisitCreatedEntries(HCR_FRAMEBUFFER hFb, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB pfnVisitorCb, void *pvContext);
 int CrFbResize(HCR_FRAMEBUFFER hFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM);
-int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, uint32_t cRects, const RTRECT *pPrects, CR_BLITTER_IMG *pImg);
+int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pPrects, CR_BLITTER_IMG *pImg);
 bool CrFbIsEnabled(HCR_FRAMEBUFFER hFb);
 int CrFbEntryCreateForTexId(HCR_FRAMEBUFFER hFb, GLuint idTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry);
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c	(revision 50753)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c	(revision 50754)
@@ -3186,6 +3186,46 @@
 }
 
-static int32_t crVBoxServerCrCmdProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd)
-{
+static DECLCALLBACK(int) crVBoxCrCmdEnable(HVBOXCRCMDSVR hSvr, VBOXCRCMD_SVRENABLE_INFO *pInfo)
+{
+    cr_server.CrCmdClientInfo = *pInfo;
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdDisable(HVBOXCRCMDSVR hSvr)
+{
+    AssertFailed();
+    memset(&cr_server.CrCmdClientInfo, 0, sizeof (cr_server.CrCmdClientInfo));
+    return VERR_NOT_IMPLEMENTED;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdHostCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
+{
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdGuestCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
+{
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdSaveState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM)
+{
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdLoadState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM, uint32_t u32Version)
+{
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd)
+{
+    AssertFailed();
     switch (pCmd->u8OpCode)
     {
@@ -3219,27 +3259,4 @@
 }
 
-int32_t crVBoxServerCrCmdNotifyCmds()
-{
-    PVBOXCMDVBVA_HDR pCmd = NULL;
-    uint32_t cbCmd;
-
-    for (;;)
-    {
-        int rc = cr_server.CltInfo.pfnCmdGet(cr_server.CltInfo.hClient, &pCmd, &cbCmd);
-        if (rc == VINF_EOF)
-            return VINF_SUCCESS;
-        if (!RT_SUCCESS(rc))
-            return rc;
-
-        rc = crVBoxServerCrCmdProcess(pCmd, cbCmd);
-        if (!RT_SUCCESS(rc))
-            return rc;
-    }
-
-    /* should not be here! */
-    AssertFailed();
-    return VERR_INTERNAL_ERROR;
-}
-
 /* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
  *
@@ -3594,5 +3611,12 @@
             g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
             g_cbVRam = pSetup->cbVRam;
-            cr_server.CltInfo = *pSetup->pCrCmdClientInfo;
+            pSetup->CrCmdServerInfo.hSvr = NULL;
+            pSetup->CrCmdServerInfo.pfnEnable = crVBoxCrCmdEnable;
+            pSetup->CrCmdServerInfo.pfnDisable = crVBoxCrCmdDisable;
+            pSetup->CrCmdServerInfo.pfnCmd = crVBoxCrCmdCmd;
+            pSetup->CrCmdServerInfo.pfnHostCtl = crVBoxCrCmdHostCtl;
+            pSetup->CrCmdServerInfo.pfnGuestCtl = crVBoxCrCmdGuestCtl;
+            pSetup->CrCmdServerInfo.pfnSaveState = crVBoxCrCmdSaveState;
+            pSetup->CrCmdServerInfo.pfnLoadState = crVBoxCrCmdLoadState;
             rc = VINF_SUCCESS;
             break;
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp	(revision 50753)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp	(revision 50754)
@@ -687,5 +687,6 @@
             || pScreen->u16BitsPerPixel != 32)
     {
-        RTRECT Rect;
+        RTRECT SrcRect;
+        RTRECT DstRect;
 
         pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height;
@@ -711,9 +712,13 @@
         pScreenshot->Img.bpp = 32;
         pScreenshot->Img.pitch = pitch;
-        Rect.xLeft = 0;
-        Rect.yTop = 0;
-        Rect.xRight = pScreen->u32Width;
-        Rect.yBottom = pScreen->u32Height;
-        int rc = CrFbBltGetContents(hFb, &Rect, 1, &Rect, &pScreenshot->Img);
+        SrcRect.xLeft = 0;
+        SrcRect.yTop = 0;
+        SrcRect.xRight = pScreen->u32Width;
+        SrcRect.yBottom = pScreen->u32Height;
+        DstRect.xLeft = 0;
+        DstRect.yTop = 0;
+        DstRect.xRight = width;
+        DstRect.yBottom = height;
+        int rc = CrFbBltGetContents(hFb, &SrcRect, &DstRect, 1, &DstRect, &pScreenshot->Img);
         if (!RT_SUCCESS(rc))
         {
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp	(revision 50753)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp	(revision 50754)
@@ -320,4 +320,62 @@
 }
 
+static void crFbBltImgScaledRects(const CR_BLITTER_IMG *pSrc, const RTPOINT *pSrcDataPoint, bool fSrcInvert, const RTRECT *pCopyRect, const RTPOINT *pDstDataPoint, float strX, float strY, CR_BLITTER_IMG *pDst)
+{
+    int32_t srcX = pCopyRect->xLeft - pSrcDataPoint->x;
+    int32_t srcY = pCopyRect->yTop - pSrcDataPoint->y;
+    Assert(srcX >= 0);
+    Assert(srcY >= 0);
+
+    RTRECT UnscaledCopyRect;
+    VBoxRectUnscaled(pCopyRect, strX, strY, &UnscaledCopyRect);
+
+    srcX = CR_FLOAT_RCAST(int32_t, srcX / strX);
+    srcY = CR_FLOAT_RCAST(int32_t, srcY / strY);
+
+    int32_t UnscaledSrcWidth = UnscaledCopyRect.xRight - UnscaledCopyRect.xLeft;
+    int32_t delta = (int32_t)pSrc->width - srcX - UnscaledSrcWidth;
+    if (delta < 0)
+        UnscaledSrcWidth += delta;
+
+    if (UnscaledSrcWidth <= 0)
+    {
+        LOG(("UnscaledSrcWidth <= 0"));
+        if (UnscaledSrcWidth < 0)
+            WARN(("src width (%d) < 0", UnscaledSrcWidth));
+        return;
+    }
+
+    int32_t UnscaledSrcHeight = UnscaledCopyRect.yBottom - UnscaledCopyRect.yTop;
+    delta = (int32_t)pSrc->height - srcY - UnscaledSrcHeight;
+    if (delta < 0)
+        UnscaledSrcHeight += delta;
+
+    if (UnscaledSrcHeight <= 0)
+    {
+        LOG(("UnscaledSrcHeight <= 0"));
+        if (UnscaledSrcHeight < 0)
+            WARN(("src height (%d) < 0", UnscaledSrcHeight));
+        return;
+    }
+
+    int32_t dstX = pCopyRect->xLeft - pDstDataPoint->x;
+    int32_t dstY = pCopyRect->yTop - pDstDataPoint->y;
+    Assert(dstX >= 0);
+    Assert(dstY >= 0);
+
+
+    uint8_t *pu8Src = ((uint8_t*)pSrc->pvData) + pSrc->pitch * (!fSrcInvert ? srcY : pSrc->height - srcY - 1) + srcX * 4;
+    uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * dstY + dstX * 4;
+
+    CrBmpScale32(pu8Dst, pDst->pitch,
+                        pCopyRect->xRight - pCopyRect->xLeft,
+                        pCopyRect->yBottom - pCopyRect->yTop,
+                        pu8Src,
+                        fSrcInvert ? -pSrc->pitch : pSrc->pitch,
+                        UnscaledSrcWidth,
+                        UnscaledSrcHeight
+                        );
+}
+
 static void crFbImgFromScreenVram(const VBVAINFOSCREEN *pScreen, void *pvVram, CR_BLITTER_IMG *pImg)
 {
@@ -338,5 +396,5 @@
 }
 
-static int crFbBltGetContentsDirect(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+static int crFbBltGetContentsDirect(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
 {
     VBOXVR_LIST List;
@@ -348,13 +406,15 @@
 
     VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
-    RTPOINT SrcPoint = {pSrcRect->xLeft, pSrcRect->yTop};
-    float strX = ((float)pImg->width) / (pSrcRect->xRight - pSrcRect->xLeft);
-    float strY = ((float)pImg->height) / (pSrcRect->yBottom - pSrcRect->yTop);
-
-    RTPOINT ScaledSrcPoint;
-    ScaledSrcPoint.x = CR_FLOAT_RCAST(int32_t, strX * SrcPoint.x);
-    ScaledSrcPoint.y = CR_FLOAT_RCAST(int32_t, strY * SrcPoint.y);
-
-    RTPOINT ZeroPoint = {0, 0};
+    int32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft;
+    int32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop;
+    int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
+    int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
+
+    RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop};
+    float strX = ((float)dstWidth) / srcWidth;
+    float strY = ((float)dstHeight) / srcHeight;
+    bool fScale = (dstWidth != srcWidth || dstHeight != srcHeight);
+
+    const RTPOINT ZeroPoint = {0, 0};
 
     VBoxVrListInit(&List);
@@ -388,16 +448,22 @@
         }
 
-        for (uint32_t i = 0; i < cRects; ++i)
-        {
-            const RTRECT * pRect = &pRects[i];
-            for (uint32_t j = 0; j < cRegions; ++j)
+        for (uint32_t j = 0; j < cRegions; ++j)
+        {
+            /* rects are in dst coordinates,
+             * while the pReg is in source coords
+             * convert */
+            const RTRECT * pReg = &pRegions[j];
+            RTRECT ScaledReg;
+            /* scale */
+            VBoxRectScaled(pReg, strX, strY, &ScaledReg);
+            /* translate */
+            VBoxRectTranslate(&ScaledReg, pDstRect->xLeft, pDstRect->yTop);
+
+            for (uint32_t i = 0; i < cRects; ++i)
             {
-                const RTRECT * pReg = &pRegions[j];
+                const RTRECT * pRect = &pRects[i];
+
                 RTRECT Intersection;
-                VBoxRectIntersected(pRect, pReg, &Intersection);
-                if (VBoxRectIsZero(&Intersection))
-                    continue;
-
-                VBoxRectScale(&Intersection, strX, strY);
+                VBoxRectIntersected(pRect, &ScaledReg, &Intersection);
                 if (VBoxRectIsZero(&Intersection))
                     continue;
@@ -455,6 +521,6 @@
                     width = CR_FLOAT_RCAST(uint32_t, strX * pVrTex->width);
                     height = CR_FLOAT_RCAST(uint32_t, strY * pVrTex->height);
-                    ScaledEntryPoint.x = CR_FLOAT_RCAST(int32_t, strX * CrVrScrCompositorEntryRectGet(pEntry)->xLeft);
-                    ScaledEntryPoint.y = CR_FLOAT_RCAST(int32_t, strY * CrVrScrCompositorEntryRectGet(pEntry)->yTop);
+                    ScaledEntryPoint.x = CR_FLOAT_RCAST(int32_t, strX * CrVrScrCompositorEntryRectGet(pEntry)->xLeft) + pDstRect->xLeft;
+                    ScaledEntryPoint.y = CR_FLOAT_RCAST(int32_t, strY * CrVrScrCompositorEntryRectGet(pEntry)->yTop) + pDstRect->yTop;
                 }
 
@@ -468,5 +534,5 @@
                 bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS);
 
-                crFbBltImg(pSrcImg, &ScaledEntryPoint, fInvert, &Intersection, &ScaledSrcPoint, pImg);
+                crFbBltImg(pSrcImg, &ScaledEntryPoint, fInvert, &Intersection, &ZeroPoint, pImg);
 
                 CrTdBltDataReleaseScaled(pTex, pSrcImg);
@@ -503,16 +569,245 @@
         }
 
+        const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor);
+
+        CR_BLITTER_IMG FbImg;
+
+        crFbImgFromFb(hFb, &FbImg);
+
+        for (uint32_t j = 0; j < c2DRects; ++j)
+        {
+            const RTRECT * p2DRect = &p2DRects[j];
+            RTRECT ScaledReg;
+            /* scale */
+            VBoxRectScaled(p2DRect, strX, strY, &ScaledReg);
+            /* translate */
+            VBoxRectTranslate(&ScaledReg, pDstRect->xLeft, pDstRect->yTop);
+
+            for (uint32_t i = 0; i < cRects; ++i)
+            {
+                const RTRECT * pRect = &pRects[i];
+                RTRECT Intersection;
+
+                VBoxRectIntersected(pRect, &ScaledReg, &Intersection);
+                if (VBoxRectIsZero(&Intersection))
+                    continue;
+
+                if (!fScale)
+                    crFbBltImg(&FbImg, &DstPoint, false, &Intersection, &ZeroPoint, pImg);
+                else
+                    crFbBltImgScaledRects(&FbImg, &DstPoint, false, &Intersection, &ZeroPoint, strX, strY, pImg);
+            }
+        }
+    }
+
+end:
+
+    if (pEnteredTex)
+        CrTdBltLeave(pEnteredTex);
+
+    if (pEnteredBlitter)
+        CrBltLeave(pEnteredBlitter);
+
+    VBoxVrListClear(&List);
+
+    return rc;
+}
+
+static int crFbBltGetContentsScaleCPU(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+    int32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft;
+    int32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop;
+    int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
+    int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
+
+    RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop};
+    float strX = ((float)dstWidth) / srcWidth;
+    float strY = ((float)dstHeight) / srcHeight;
+
+    RTRECT DstRect;
+    VBoxRectUnscaled(pDstRect, strX, strY, &DstRect);
+    DstRect.xRight = DstRect.xLeft + srcWidth;
+    DstRect.yBottom = DstRect.yTop + srcHeight;
+
+    /* destination is bigger than the source, do 3D data stretching with CPU */
+    CR_BLITTER_IMG Img;
+    Img.cbData = srcWidth * srcHeight * 4;
+    Img.pvData = RTMemAlloc(Img.cbData);
+    if (!Img.pvData)
+    {
+        WARN(("RTMemAlloc Failed"));
+        return VERR_NO_MEMORY;
+    }
+    Img.enmFormat = pImg->enmFormat;
+    Img.width = srcWidth;
+    Img.height = srcHeight;
+    Img.bpp = pImg->bpp;
+    Img.pitch = Img.width * 4;
+
+    int rc = CrFbBltGetContents(hFb, pSrcRect, &DstRect, cRects, pRects, &Img);
+    if (RT_SUCCESS(rc))
+    {
+        CrBmpScale32((uint8_t *)pImg->pvData,
+                            pImg->pitch,
+                            pImg->width, pImg->height,
+                            (const uint8_t *)Img.pvData,
+                            Img.pitch,
+                            Img.width, Img.height);
+    }
+    else
+        WARN(("CrFbBltGetContents failed %d", rc));
+
+    RTMemFree(Img.pvData);
+
+    return rc;
+
+}
+
+int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+    uint32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft;
+    uint32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop;
+    uint32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
+    uint32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
+    if ((srcWidth == dstWidth
+            && srcHeight == dstHeight)
+            || !CrFbHas3DData(hFb)
+            || (srcWidth * srcHeight > dstWidth * dstHeight))
+    {
+        return crFbBltGetContentsDirect(hFb, pSrcRect, pDstRect, cRects, pRects, pImg);
+    }
+
+    return crFbBltGetContentsScaleCPU(hFb, pSrcRect, pDstRect, cRects, pRects, pImg);
+}
+
+#if 0
+static int crFbBltPutContentsVram(HCR_FRAMEBUFFER hFb, const RTPOINT *pDstPoint, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg, float strX, float strY)
+{
+    const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor);
+    const RTPOINT ZeroPoint = {0};
+
+    uint32_t fbWidth = (pCompRect->xRight - pCompRect->xLeft);
+    uint32_t fbHeight = pCompRect->yBottom - pCompRect->yTop;
+
+    uint32_t stretchedWidth = CR_FLOAT_RCAST(uint32_t, strX * fbWidth);
+    uint32_t stretchedHeight = CR_FLOAT_RCAST(uint32_t, strY * fbHeight);
+
+    CR_BLITTER_IMG FbImg;
+
+    bool fScale = fbWidth != stretchedWidth || fbHeight != stretchedHeight;
+
+    crFbImgFromFb(hFb, &FbImg);
+
+    RTRECT Intersection;
+
+    for (uint32_t i = 0; i < cRects; ++i)
+    {
+        const RTRECT * pRect = &pRects[i];
+        VBoxRectIntersected(pRect, pCompRect, &Intersection);
+
+        if (VBoxRectIsZero(&Intersection))
+            continue;
+
+        if (!fScale)
+            crFbBltImg(pImg, pDstPoint, false, &Intersection, &ZeroPoint, &FbImg);
+        else
+            crFbBltImgScaled(pImg, pDstPoint, false, &Intersection, &ZeroPoint, strX, strY, &FbImg);
+    }
+
+    return VINF_SUCCESS;
+}
+
+int CrFbBltPutContents(HCR_FRAMEBUFFER hFb, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+    RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop};
+    float strX = ((float)pImg->width) / (pDstRect->xRight - pDstRect->xLeft);
+    float strY = ((float)pImg->height) / (pDstRect->yBottom - pDstRect->yTop);
+
+    int rc = CrFbEntryRegionsAdd(hFb, NULL, const RTPOINT *pPos, cRects, pRects, true)
+    if (!hFb->cUpdating)
+    {
+        WARN(("not updating\n"));
+        return VERR_INVALID_STATE;
+    }
+}
+
+int CrFbBltPutContentsNe(HCR_FRAMEBUFFER hFb, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+    uint32_t cCompRects;
+    const RTRECT *pCompRects;
+    int rc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cCompRects, NULL, NULL, &pCompRects);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("CrVrScrCompositorRegionsGet failed rc %d", rc));
+        return rc;
+    }
+
+    bool fRegChanged = false;
+    for (uint32_t i = 0; i < cCompRects; ++i)
+    {
+        const RTRECT *pCompRect = pCompRects[i];
+        for (uint32_t j = 0; j < cRects; ++j)
+        {
+            const RTRECT *pRect = pRects[j];
+            if (VBoxRectIsIntersect(pCompRect, pRect))
+            {
+                fRegChanged = true;
+                break;
+            }
+        }
+    }
+
+    if (fRegChanged)
+    {
+        rc = CrFbUpdateBegin(hFb);
+        if (RT_SUCCESS(rc))
+        {
+            rc = CrFbBltPutContents(hFb, pDstRect, cRects, pRects, pImg);
+            if (!RT_SUCCESS(rc))
+                WARN(("CrFbBltPutContents failed rc %d", rc));
+            CrFbUpdateEnd(hFb);
+        }
+        else
+            WARN(("CrFbUpdateBegin failed rc %d", rc));
+
+        return rc;
+    }
+
+    return crFbBltPutContentsVram(HCR_FRAMEBUFFER hFb, const RTPOINT *pDstPoint, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg, float strX, float strY);
+
+    const RTPOINT ZeroPoint = {0, 0};
+
+    c2DRects = VBoxVrListRectsCount(&List);
+    if (c2DRects)
+    {
+        if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT))
+        {
+            if (g_CrPresenter.pvTmpBuf2)
+                RTMemFree(g_CrPresenter.pvTmpBuf2);
+
+            g_CrPresenter.cbTmpBuf2 = (c2DRects + 10) * sizeof (RTRECT);
+            g_CrPresenter.pvTmpBuf2 = RTMemAlloc(g_CrPresenter.cbTmpBuf2);
+            if (!g_CrPresenter.pvTmpBuf2)
+            {
+                WARN(("RTMemAlloc failed!"));
+                g_CrPresenter.cbTmpBuf2 = 0;
+                rc = VERR_NO_MEMORY;
+                goto end;
+            }
+        }
+
+        RTRECT *p2DRects  = (RTRECT *)g_CrPresenter.pvTmpBuf2;
+
+        rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects);
+        if (!RT_SUCCESS(rc))
+        {
+            WARN(("VBoxVrListRectsGet failed, rc %d", rc));
+            goto end;
+        }
+
         RTPOINT Pos = {0};
         const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor);
 
-        uint32_t fbWidth = (pCompRect->xRight - pCompRect->xLeft);
-        uint32_t fbHeight = pCompRect->yBottom - pCompRect->yTop;
-
-        uint32_t stretchedWidth = CR_FLOAT_RCAST(uint32_t, strX * fbWidth);
-        uint32_t stretchedHeight = CR_FLOAT_RCAST(uint32_t, strY * fbHeight);
-
         CR_BLITTER_IMG FbImg;
-
-        bool fScale = fbWidth != stretchedWidth || fbHeight != stretchedHeight;
 
         crFbImgFromFb(hFb, &FbImg);
@@ -549,59 +844,5 @@
     return rc;
 }
-
-static int crFbBltGetContentsScaleCPU(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
-{
-    uint32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft;
-    uint32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop;
-
-    /* destination is bigger than the source, do 3D data stretching with CPU */
-    CR_BLITTER_IMG Img;
-    Img.cbData = srcWidth * srcHeight * 4;
-    Img.pvData = RTMemAlloc(Img.cbData);
-    if (!Img.pvData)
-    {
-        WARN(("RTMemAlloc Failed"));
-        return VERR_NO_MEMORY;
-    }
-    Img.enmFormat = pImg->enmFormat;
-    Img.width = srcWidth;
-    Img.height = srcHeight;
-    Img.bpp = pImg->bpp;
-    Img.pitch = Img.width * 4;
-
-    int rc = CrFbBltGetContents(hFb, pSrcRect, cRects, pRects, &Img);
-    if (RT_SUCCESS(rc))
-    {
-        CrBmpScale32((uint8_t *)pImg->pvData,
-                            pImg->pitch,
-                            pImg->width, pImg->height,
-                            (const uint8_t *)Img.pvData,
-                            Img.pitch,
-                            Img.width, Img.height);
-    }
-    else
-        WARN(("CrFbBltGetContents failed %d", rc));
-
-    RTMemFree(Img.pvData);
-
-    return rc;
-
-}
-
-int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
-{
-    uint32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft;
-    uint32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop;
-    if ((srcWidth == pImg->width
-            && srcHeight == pImg->height)
-            || !CrFbHas3DData(hFb)
-            || (srcWidth * srcHeight > pImg->width * pImg->height))
-    {
-        return crFbBltGetContentsDirect(hFb, pSrcRect, cRects, pRects, pImg);
-    }
-
-    return crFbBltGetContentsScaleCPU(hFb, pSrcRect, cRects, pRects, pImg);
-}
-
+#endif
 
 int CrFbResize(CR_FRAMEBUFFER *pFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM)
@@ -4473,4 +4714,5 @@
                     uint8_t *pu8Buf = g_pvVRamBase + offVRAM;
                     texId = 0;
+//                    cr_server.CrCmdClientInfo.pfnCltScrUpdateBegin(cr_server.CrCmdClientInfo.hCltScr);
                     /*todo: notify VGA device to perform updates */
                 }
@@ -4512,12 +4754,17 @@
                 uint8_t *pu8Buf = g_pvVRamBase + offVRAM;
 
-                RTRECT Rect;
-                Rect.xLeft = pBlt->Pos.x;
-                Rect.yTop = pBlt->Pos.y;
-                Rect.xRight = Rect.xLeft + pScreen->u32Width;
-                Rect.yBottom = Rect.yTop + pScreen->u32Height;
+                RTRECT SrcRect;
+                SrcRect.xLeft = 0;
+                SrcRect.yTop = 0;
+                SrcRect.xRight = pScreen->u32Width;
+                SrcRect.yBottom = pScreen->u32Height;
+                RTRECT DstRect;
+                DstRect.xLeft = pBlt->Pos.x;
+                DstRect.yTop = pBlt->Pos.y;
+                DstRect.xRight = DstRect.xLeft + pScreen->u32Width;
+                DstRect.yBottom = DstRect.yTop + pScreen->u32Height;
                 CR_BLITTER_IMG Img;
                 crFbImgFromScreenVram(pScreen, pu8Buf, &Img);
-                int rc = CrFbBltGetContents(hFb, &Rect, cRects, pRects, &Img);
+                int rc = CrFbBltGetContents(hFb, &SrcRect, &DstRect, cRects, pRects, &Img);
                 if (!RT_SUCCESS(rc))
                 {
Index: /trunk/src/VBox/Main/include/DisplayImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/DisplayImpl.h	(revision 50753)
+++ /trunk/src/VBox/Main/include/DisplayImpl.h	(revision 50754)
@@ -174,5 +174,7 @@
     void handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam);
 #endif
-
+    int  handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
+                                        PFNCRCTLCOMPLETION pfnCompletion,
+                                        void *pvCompletion);
 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
     void  handleCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam);
@@ -271,5 +273,9 @@
     static DECLCALLBACK(void)  displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext);
 #endif
-
+    static DECLCALLBACK(int)  displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface,
+                                        struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
+                                        PFNCRCTLCOMPLETION pfnCompletion,
+                                        void *pvCompletion);
+    static DECLCALLBACK(void)  displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext);
 #ifdef VBOX_WITH_HGSMI
     static DECLCALLBACK(int)   displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags);
Index: /trunk/src/VBox/Main/src-client/DisplayImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 50753)
+++ /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 50754)
@@ -4304,5 +4304,5 @@
 void Display::handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd)
 {
-    int rc = VERR_INVALID_FUNCTION;
+    int rc = VERR_NOT_SUPPORTED;
     VBOXHGCMSVCPARM parm;
     parm.type = VBOX_HGCM_SVC_PARM_PTR;
@@ -4332,5 +4332,5 @@
 void Display::handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl)
 {
-    int rc = VERR_INVALID_FUNCTION;
+    int rc = VERR_NOT_SUPPORTED;
     VBOXHGCMSVCPARM parm;
     parm.type = VBOX_HGCM_SVC_PARM_PTR;
@@ -4383,4 +4383,46 @@
 }
 #endif
+
+DECLCALLBACK(void)  Display::displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext)
+{
+    VBOXCRCMDCTL *pCmd = (VBOXCRCMDCTL*)pParam->u.pointer.addr;
+    if (pCmd->pfnInternal)
+        ((PFNCRCTLCOMPLETION)pCmd->pfnInternal)(pCmd, pParam->u.pointer.size, result, pvContext);
+}
+
+int  Display::handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
+                                        PFNCRCTLCOMPLETION pfnCompletion,
+                                        void *pvCompletion)
+{
+    VMMDev *pVMMDev = mParent->getVMMDev();
+    if (!pVMMDev)
+    {
+        AssertMsgFailed(("no vmmdev\n"));
+        return VERR_INVALID_STATE;
+    }
+
+    Assert(mhCrOglSvc);
+    VBOXHGCMSVCPARM parm;
+    parm.type = VBOX_HGCM_SVC_PARM_PTR;
+    parm.u.pointer.addr = pCmd;
+    parm.u.pointer.size = cbCmd;
+
+    pCmd->pfnInternal = (void(*)())pfnCompletion;
+    int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, displayCrHgcmCtlSubmitCompletion, pvCompletion);
+    if (!RT_SUCCESS(rc))
+        AssertMsgFailed(("hgcmHostFastCallAsync failed rc %n", rc));
+
+    return rc;
+}
+
+DECLCALLBACK(int)  Display::displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface,
+                                    struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
+                                    PFNCRCTLCOMPLETION pfnCompletion,
+                                    void *pvCompletion)
+{
+    PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
+    Display *pThis = pDrv->pDisplay;
+    return pThis->handleCrHgcmCtlSubmit(pCmd, cbCmd, pfnCompletion, pvCompletion);
+}
 
 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
@@ -5007,4 +5049,5 @@
     pThis->IConnector.pfnCrHgsmiControlProcess = Display::displayCrHgsmiControlProcess;
 #endif
+    pThis->IConnector.pfnCrHgcmCtlSubmit       = Display::displayCrHgcmCtlSubmit;
 #ifdef VBOX_WITH_HGSMI
     pThis->IConnector.pfnVBVAEnable            = Display::displayVBVAEnable;
