Index: /trunk/include/VBox/HostServices/VBoxCrOpenGLSvc.h
===================================================================
--- /trunk/include/VBox/HostServices/VBoxCrOpenGLSvc.h	(revision 50312)
+++ /trunk/include/VBox/HostServices/VBoxCrOpenGLSvc.h	(revision 50313)
@@ -48,4 +48,5 @@
 #define SHCRGL_HOST_FN_DEV_RESIZE          (22)
 #define SHCRGL_HOST_FN_VIEWPORT_CHANGED2 (23)
+#define SHCRGL_HOST_FN_TAKE_SCREENSHOT (24)
 /* crOpenGL guest functions */
 #define SHCRGL_GUEST_FN_WRITE       (2)
@@ -380,3 +381,18 @@
 } CRVBOXHGCMVIEWPORT;
 
+typedef DECLCALLBACKPTR(void, PFNCRSCREENSHOTREPORT)(void *pvCtx, uint32_t uScreen,
+                uint32_t x, uint32_t y, uint32_t uBitsPerPixel,
+                uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight,
+                uint8_t *pu8BufferAddress, uint64_t u64TimeStamp);
+
+#define CRSCREEN_ALL (0xffffffff)
+
+typedef struct
+{
+    /* screen id or CRSCREEN_ALL to specify all enabled */
+    uint32_t u32Screen;
+    void *pvContext;
+    PFNCRSCREENSHOTREPORT pfnScreenshot;
+} CRVBOXHGCMTAKESCREENSHOT;
+
 #endif
Index: /trunk/include/VBox/VBoxVideo.h
===================================================================
--- /trunk/include/VBox/VBoxVideo.h	(revision 50312)
+++ /trunk/include/VBox/VBoxVideo.h	(revision 50313)
@@ -1438,5 +1438,5 @@
     VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN,
     VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END,
-    VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION,
+    VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB,
     VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRCONNECT,
     VBOXVDMACMD_CHROMIUM_CTL_TYPE_SIZEHACK = 0xfffffffe
@@ -1466,10 +1466,22 @@
 typedef FNCRHGSMICMDCOMPLETION *PFNCRHGSMICMDCOMPLETION;
 
-typedef struct VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION
+typedef DECLCALLBACK(bool) FNCROGLHASDATA();
+typedef FNCROGLHASDATA *PFNCROGLHASDATA;
+
+/* callbacks chrogl gives to main */
+typedef struct CR_MAIN_INTERFACE
+{
+    PFNCROGLHASDATA pfnHasData;
+} CR_MAIN_INTERFACE;
+
+typedef struct VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB
 {
     VBOXVDMACMD_CHROMIUM_CTL Hdr;
+    /*in*/
     HCRHGSMICMDCOMPLETION hCompletion;
     PFNCRHGSMICMDCOMPLETION pfnCompletion;
-} VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION, *PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION;
+    /*out*/
+    CR_MAIN_INTERFACE MainInterface;
+} VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB, *PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB;
 
 typedef struct VBOXCRCON_SERVER *HVBOXCRCON_SERVER;
@@ -1669,8 +1681,15 @@
 } VBOXCMDVBVA_RECT;
 
+typedef struct VBOXCMDVBVA_POINT
+{
+   int16_t x;
+   int16_t y;
+} VBOXCMDVBVA_POINT;
+
 typedef struct VBOXCMDVBVA_BLT_PRIMARY
 {
     VBOXCMDVBVA_HDR Hdr;
     VBOXCMDVBVA_ALLOCINFO alloc;
+    VBOXCMDVBVA_POINT Pos;
     /* the rects count is determined from the command size */
     VBOXCMDVBVA_RECT aRects[1];
@@ -1682,4 +1701,5 @@
     VBOXCMDVBVA_ALLOCINFO src;
     VBOXCMDVBVA_ALLOCINFO dst;
+    VBOXCMDVBVA_POINT Pos;
     /* the rects count is determined from the command size */
     VBOXCMDVBVA_RECT aRects[1];
Index: /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp	(revision 50312)
+++ /trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp	(revision 50313)
@@ -5920,4 +5920,7 @@
             }
 
+            pBlt->Pos.x = pPresent->DstRect.left - pPresent->SrcRect.left;
+            pBlt->Pos.y = pPresent->DstRect.top - pPresent->SrcRect.top;
+
             paRects = pBlt->aRects;
             cbMaxRects = pPresent->DmaBufferPrivateDataSize - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects);
@@ -5939,4 +5942,7 @@
             if (VBoxCVDdiFillAllocInfo(pHdr, &pBlt->dst, pDstAlloc, pDst, true))
                 u32DstPatch = RT_OFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, dst.offVRAM);
+
+            pBlt->Pos.x = pPresent->DstRect.left - pPresent->SrcRect.left;
+            pBlt->Pos.y = pPresent->DstRect.top - pPresent->SrcRect.top;
 
             paRects = pBlt->aRects;
Index: /trunk/src/VBox/GuestHost/OpenGL/include/cr_blitter.h
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/include/cr_blitter.h	(revision 50312)
+++ /trunk/src/VBox/GuestHost/OpenGL/include/cr_blitter.h	(revision 50313)
@@ -285,4 +285,5 @@
  * Must be called wit data released (CrTdBltDataRelease) */
 VBOXBLITTERDECL(int) CrTdBltDataDiscard(PCR_TEXDATA pTex);
+VBOXBLITTERDECL(int) CrTdBltDataDiscardNe(PCR_TEXDATA pTex);
 /* does same as CrTdBltDataDiscard, and in addition cleans up.
  * this is kind of a texture destructor, which clients should call on texture object destruction, e.g. from the PFNCRTEXDATA_RELEASED callback */
Index: /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h	(revision 50312)
+++ /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h	(revision 50313)
@@ -34,6 +34,4 @@
 #include <VBox/Hardware/VBoxVideoVBE.h>
 #include <VBox/VBoxVideo3D.h>
-
-#include "cr_vreg.h"
 
 #ifdef __cplusplus
@@ -521,4 +519,14 @@
 extern DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version);
 
+typedef struct
+{
+    CR_BLITTER_IMG Img;
+    uint32_t u32Screen;
+    uint32_t fDataIsFbDirect;
+} CR_SCREENSHOT;
+
+extern DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, CR_SCREENSHOT *pScreenshot);
+extern DECLEXPORT(void) crServerVBoxScreenshotRelease(CR_SCREENSHOT *pScreenshot);
+
 extern DECLEXPORT(void) crServerVBoxCompositionSetEnableStateGlobal(GLboolean fEnable);
 extern DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount);
Index: /trunk/src/VBox/GuestHost/OpenGL/include/cr_vreg.h
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/include/cr_vreg.h	(revision 50312)
+++ /trunk/src/VBox/GuestHost/OpenGL/include/cr_vreg.h	(revision 50313)
@@ -95,4 +95,17 @@
 }
 
+DECLINLINE(void) VBoxRectInvertY(RTRECT * pRect)
+{
+    int32_t y = pRect->yTop;
+    pRect->yTop = pRect->yBottom;
+    pRect->yBottom = y;
+}
+
+DECLINLINE(void) VBoxRectInvertedY(const RTRECT * pRect, RTRECT * pResult)
+{
+    *pResult = *pRect;
+    VBoxRectInvertY(pResult);
+}
+
 DECLINLINE(void) VBoxRectMove(RTRECT * pRect, int32_t x, int32_t y)
 {
Index: /trunk/src/VBox/GuestHost/OpenGL/util/blitter.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/util/blitter.cpp	(revision 50312)
+++ /trunk/src/VBox/GuestHost/OpenGL/util/blitter.cpp	(revision 50313)
@@ -1290,4 +1290,30 @@
 }
 
+VBOXBLITTERDECL(int) CrTdBltDataDiscardNe(PCR_TEXDATA pTex)
+{
+    if (!pTex->Img.pvData)
+        return VINF_SUCCESS;
+
+    bool fEntered = false;
+    if (pTex->idPBO)
+    {
+        int rc = CrTdBltEnter(pTex);
+        if (!RT_SUCCESS(rc))
+        {
+            WARN(("err"));
+            return rc;
+        }
+
+        fEntered = true;
+    }
+
+    crTdBltImgFree(pTex);
+
+    if (fEntered)
+        CrTdBltLeave(pTex);
+
+    return VINF_SUCCESS;
+}
+
 static void crTdBltDataCleanup(PCR_TEXDATA pTex)
 {
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp	(revision 50312)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp	(revision 50313)
@@ -43,4 +43,5 @@
 PVBOXHGCMSVCHELPERS g_pHelpers;
 static IConsole* g_pConsole = NULL;
+static uint32_t g_u32ScreenCount = 0;
 static PVM g_pVM = NULL;
 
@@ -1025,4 +1026,5 @@
 
                     g_pConsole = pConsole;
+                    g_u32ScreenCount = monitorCount;
 
                     rc = crVBoxServerSetScreenCount(monitorCount);
@@ -1183,4 +1185,84 @@
 
                 rc = VINF_SUCCESS;
+            }
+            break;
+        }
+        case SHCRGL_HOST_FN_TAKE_SCREENSHOT:
+        {
+            if (cParms != 1)
+            {
+                LogRel(("SHCRGL_HOST_FN_TAKE_SCREENSHOT: cParms invalid - %d", cParms));
+                rc = VERR_INVALID_PARAMETER;
+                break;
+            }
+
+            if (paParms->type != VBOX_HGCM_SVC_PARM_PTR)
+            {
+                AssertMsgFailed(("invalid param\n"));
+                rc = VERR_INVALID_PARAMETER;
+                break;
+            }
+
+            if (!paParms->u.pointer.addr)
+            {
+                AssertMsgFailed(("invalid param\n"));
+                rc = VERR_INVALID_PARAMETER;
+                break;
+            }
+
+            if (paParms->u.pointer.size != sizeof (CRVBOXHGCMTAKESCREENSHOT))
+            {
+                AssertMsgFailed(("invalid param\n"));
+                rc = VERR_INVALID_PARAMETER;
+                break;
+            }
+
+            CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)paParms->u.pointer.addr;
+            uint64_t u64Now = RTTimeProgramMilliTS();
+
+            if (pScreenshot->u32Screen == CRSCREEN_ALL)
+            {
+                for (uint32_t i = 0; i < g_u32ScreenCount; ++i)
+                {
+                    CR_SCREENSHOT Screenshot;
+
+                    int rc = crServerVBoxScreenshotGet(i, &Screenshot);
+                    if (RT_SUCCESS(rc))
+                    {
+                        pScreenshot->pfnScreenshot(pScreenshot->pvContext, i,
+                                0, 0, 32,
+                                Screenshot.Img.pitch, Screenshot.Img.width, Screenshot.Img.height,
+                                (uint8_t*)Screenshot.Img.pvData, u64Now);
+                        crServerVBoxScreenshotRelease(&Screenshot);
+                    }
+                    else
+                    {
+                        Assert(rc == VERR_INVALID_STATE);
+                    }
+                }
+            }
+            else if (pScreenshot->u32Screen < g_u32ScreenCount)
+            {
+                CR_SCREENSHOT Screenshot;
+
+                int rc = crServerVBoxScreenshotGet(pScreenshot->u32Screen, &Screenshot);
+                if (RT_SUCCESS(rc))
+                {
+                    pScreenshot->pfnScreenshot(pScreenshot->pvContext, pScreenshot->u32Screen,
+                            0, 0, 32,
+                            Screenshot.Img.pitch, Screenshot.Img.width, Screenshot.Img.height,
+                            (uint8_t*)Screenshot.Img.pvData, u64Now);
+                    crServerVBoxScreenshotRelease(&Screenshot);
+                }
+                else
+                {
+                    Assert(rc == VERR_INVALID_STATE);
+                }
+            }
+            else
+            {
+                AssertMsgFailed(("invalid screen id\n"));
+                rc = VERR_INVALID_PARAMETER;
+                break;
             }
             break;
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h	(revision 50312)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h	(revision 50313)
@@ -389,4 +389,9 @@
 }
 
+DECLINLINE(void) CrFBmSetAtomic(CR_FBMAP *pMap, uint32_t i)
+{
+    return ASMAtomicBitSet(&pMap->Map, i);
+}
+
 DECLINLINE(void) CrFBmClear(CR_FBMAP *pMap, uint32_t i)
 {
@@ -400,4 +405,5 @@
 HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled();
 HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb);
+HCR_FRAMEBUFFER CrPMgrFbGetEnabled(uint32_t idScreen);
 int CrPMgrModeVrdp(bool fEnable);
 int CrPMgrModeRootVr(bool fEnable);
@@ -416,6 +422,8 @@
 typedef DECLCALLBACKPTR(bool, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB)(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext);
 
+bool CrFbHas3DData(HCR_FRAMEBUFFER hFb);
 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 RTPOINT *pPoint, 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);
@@ -424,4 +432,5 @@
 void CrFbEntryRelease(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry);
 const struct VBVAINFOSCREEN* CrFbGetScreenInfo(HCR_FRAMEBUFFER hFb);
+void* CrFbGetVRAM(HCR_FRAMEBUFFER hFb);
 const struct VBOXVR_SCR_COMPOSITOR* CrFbGetCompositor(HCR_FRAMEBUFFER hFb);
 const struct VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbEntryGetCompositorEntry(HCR_FRAMEBUFFER_ENTRY hEntry);
@@ -451,4 +460,6 @@
 CR_TEXDATA* CrFbTexDataCreate(const VBOXVR_TEXTURE *pTex);
 void CrFbTexDataInit(CR_TEXDATA* pFbTex, const VBOXVR_TEXTURE *pTex, PFNCRTEXDATA_RELEASED pfnTextureReleased);
+
+int32_t crVBoxServerCrCmdBltProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd);
 
 //#define VBOX_WITH_CRSERVER_DUMPER
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c	(revision 50312)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c	(revision 50313)
@@ -2881,17 +2881,5 @@
 
 #ifdef VBOX_WITH_CRHGSMI
-/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
- *
- * For now we need the notion of CrHgdmi commands in the crserver_lib to be able to complete it asynchronously once it is really processed.
- * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
- * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
- * to block the lower-priority thread trying to complete the blocking command.
- * And removed extra memcpy done on blocked command arrival.
- *
- * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
- * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
- *
- * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
- * */
+
 static int32_t crVBoxServerCmdVbvaCrCmdProcess(struct VBOXCMDVBVA_CRCMD_CMD *pCmd)
 {
@@ -3193,4 +3181,75 @@
 }
 
+static int32_t crVBoxServerCrCmdProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd)
+{
+    switch (pCmd->u8OpCode)
+    {
+        case VBOXCMDVBVA_OPTYPE_CRCMD:
+        {
+            VBOXCMDVBVA_CRCMD *pCrCmdDr = (VBOXCMDVBVA_CRCMD*)pCmd;
+            VBOXCMDVBVA_CRCMD_CMD *pCrCmd = &pCrCmdDr->Cmd;
+            int rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd);
+            if (RT_SUCCESS(rc))
+            {
+            /* success */
+                pCmd->i8Result = 0;
+            }
+            else
+            {
+                crWarning("crVBoxServerCmdVbvaCrCmdProcess failed, rc %d", rc);
+                pCmd->i8Result = -1;
+            }
+            break;
+        }
+        case VBOXCMDVBVA_OPTYPE_BLT_OFFPRIMSZFMT_OR_ID:
+        {
+            crVBoxServerCrCmdBltProcess(pCmd, cbCmd);
+            break;
+        }
+        default:
+            WARN(("unsupported command"));
+            pCmd->i8Result = -1;
+    }
+    return VINF_SUCCESS;
+}
+
+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.
+ *
+ * For now we need the notion of CrHgdmi commands in the crserver_lib to be able to complete it asynchronously once it is really processed.
+ * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
+ * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
+ * to block the lower-priority thread trying to complete the blocking command.
+ * And removed extra memcpy done on blocked command arrival.
+ *
+ * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
+ * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
+ *
+ * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
+ * */
+
+
 int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
 {
@@ -3505,4 +3564,18 @@
 }
 
+static DECLCALLBACK(bool) crVBoxServerHasData()
+{
+    HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
+    for (;
+            hFb;
+            hFb = CrPMgrFbGetNextEnabled(hFb))
+    {
+        if (CrFbHas3DData(hFb))
+            return true;
+    }
+
+    return false;
+}
+
 int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
 {
@@ -3524,9 +3597,12 @@
             rc = VINF_SUCCESS;
             break;
-        case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
-        {
-            PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
+        case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB:
+        {
+            PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB)pCtl;
             g_hCrHgsmiCompletion = pSetup->hCompletion;
             g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
+
+            pSetup->MainInterface.pfnHasData = crVBoxServerHasData;
+
             rc = VINF_SUCCESS;
             break;
@@ -3546,53 +3622,3 @@
 }
 
-static int32_t crVBoxServerCrCmdProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd)
-{
-    switch (pCmd->u8OpCode)
-    {
-        case VBOXCMDVBVA_OPTYPE_CRCMD:
-        {
-            VBOXCMDVBVA_CRCMD *pCrCmdDr = (VBOXCMDVBVA_CRCMD*)pCmd;
-            VBOXCMDVBVA_CRCMD_CMD *pCrCmd = &pCrCmdDr->Cmd;
-            int rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd);
-            if (RT_SUCCESS(rc))
-            {
-            /* success */
-                pCmd->i8Result = 0;
-            }
-            else
-            {
-                crWarning("crVBoxServerCmdVbvaCrCmdProcess failed, rc %d", rc);
-                pCmd->i8Result = -1;
-            }
-            break;
-        }
-        default:
-            crWarning("unsupported command");
-            pCmd->i8Result = -1;
-    }
-    return VINF_SUCCESS;
-}
-
-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;
-}
-#endif
+#endif
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp	(revision 50312)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp	(revision 50313)
@@ -654,24 +654,71 @@
 }
 
-static void crServerCopySubImage(char *pDst, char* pSrc, CRrecti *pRect, int srcWidth, int srcHeight)
-{
-    int i;
-    int dstrowsize = 4*(pRect->x2-pRect->x1);
-    int srcrowsize = 4*srcWidth;
-    int height = pRect->y2-pRect->y1;
-
-    pSrc += 4*pRect->x1 + srcrowsize*(srcHeight-1-pRect->y1);
-
-    for (i=0; i<height; ++i)
-    {
-        crMemcpy(pDst, pSrc, dstrowsize);
-
-        pSrc -= srcrowsize;
-        pDst += dstrowsize;
-    }
-}
-
 DECLEXPORT(void) crServerVBoxCompositionSetEnableStateGlobal(GLboolean fEnable)
 {
+}
+
+DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, CR_SCREENSHOT *pScreenshot)
+{
+    HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32Screen);
+    if (!hFb)
+        return VERR_INVALID_STATE;
+
+    const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+
+    if (CrFbHas3DData(hFb))
+    {
+        RTPOINT Pos = {0, 0};
+        RTRECT Rect;
+
+        pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height;
+        pScreenshot->Img.pvData = RTMemAlloc(pScreenshot->Img.cbData);
+        if (!pScreenshot->Img.pvData)
+        {
+            WARN(("RTMemAlloc failed"));
+            return VERR_NO_MEMORY;
+        }
+        pScreenshot->Img.enmFormat = GL_BGRA;
+        pScreenshot->Img.width = pScreen->u32Width;
+        pScreenshot->Img.height = pScreen->u32Height;
+        pScreenshot->Img.bpp = pScreen->u16BitsPerPixel;
+        pScreenshot->Img.pitch = pScreen->u32LineSize;
+        Rect.xLeft = 0;
+        Rect.yTop = 0;
+        Rect.xRight = pScreenshot->Img.width;
+        Rect.yBottom = pScreenshot->Img.height;
+        int rc = CrFbBltGetContents(hFb, &Pos, 1, &Rect, &pScreenshot->Img);
+        if (!RT_SUCCESS(rc))
+        {
+            WARN(("CrFbBltGetContents failed %d", rc));
+            RTMemFree(pScreenshot->Img.pvData);
+            return rc;
+        }
+        pScreenshot->fDataIsFbDirect = 0;
+    }
+    else
+    {
+        pScreenshot->Img.pvData = CrFbGetVRAM(hFb);
+        pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height;
+        pScreenshot->Img.enmFormat = GL_BGRA;
+        pScreenshot->Img.width = pScreen->u32Width;
+        pScreenshot->Img.height = pScreen->u32Height;
+        pScreenshot->Img.bpp = pScreen->u16BitsPerPixel;
+        pScreenshot->Img.pitch = pScreen->u32LineSize;
+
+        pScreenshot->fDataIsFbDirect = 1;
+    }
+
+    pScreenshot->u32Screen = u32Screen;
+
+    return VINF_SUCCESS;
+}
+
+DECLEXPORT(void) crServerVBoxScreenshotRelease(CR_SCREENSHOT *pScreenshot)
+{
+    if (!pScreenshot->fDataIsFbDirect)
+    {
+        RTMemFree(pScreenshot->Img.pvData);
+        pScreenshot->fDataIsFbDirect = 1;
+    }
 }
 
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp	(revision 50312)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp	(revision 50313)
@@ -105,4 +105,8 @@
     CR_FBMAP FramebufferInitMap;
     CR_FRAMEBUFFER aFramebuffers[CR_MAX_GUEST_MONITORS];
+    uint32_t cbTmpBuf;
+    void *pvTmpBuf;
+    uint32_t cbTmpBuf2;
+    void *pvTmpBuf2;
 } CR_PRESENTER_GLOBALS;
 
@@ -148,4 +152,8 @@
 }
 
+void* CrFbGetVRAM(HCR_FRAMEBUFFER hFb)
+{
+    return hFb->pvVram;
+}
 
 int CrFbUpdateBegin(CR_FRAMEBUFFER *pFb)
@@ -182,4 +190,190 @@
 {
     return !!pFb->cUpdating;
+}
+
+bool CrFbHas3DData(HCR_FRAMEBUFFER hFb)
+{
+    return !CrVrScrCompositorIsEmpty(&hFb->Compositor);
+}
+
+static void crFbBltMem(uint8_t *pu8Src, int32_t cbSrcPitch, uint8_t *pu8Dst, int32_t cbDstPitch, uint32_t width, uint32_t height)
+{
+    uint32_t cbCopyRow = width * 4;
+
+    for (uint32_t i = 0; i < height; ++i)
+    {
+        memcpy(pu8Dst, pu8Src, cbCopyRow);
+
+        pu8Src += cbSrcPitch;
+        pu8Dst += cbDstPitch;
+    }
+}
+
+static void crFbBltImg(void *pvSrc, const RTRECT *pSrcDataRect, bool fSrcInvert, const RTRECT *pCopyRect, const RTPOINT *pDstDataPoint, CR_BLITTER_IMG *pDst)
+{
+    int32_t cbSrcPitch = (pSrcDataRect->xRight - pSrcDataRect->xLeft) * 4;
+    int32_t srcX = pCopyRect->xLeft - pSrcDataRect->xLeft;
+    int32_t srcY = pCopyRect->yTop - pSrcDataRect->yTop;
+    Assert(srcX >= 0);
+    Assert(srcY >= 0);
+    Assert(srcX < pSrcDataRect->xRight - pSrcDataRect->xLeft);
+    Assert(srcY < pSrcDataRect->yBottom - pSrcDataRect->yTop);
+
+    uint32_t cbDstPitch = pDst->pitch;
+    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*)pvSrc) + cbSrcPitch * (!fSrcInvert ? srcY : pSrcDataRect->yBottom - pSrcDataRect->yTop - srcY - 1) + srcX * 4;
+    uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + cbDstPitch * dstY + dstX * 4;
+    if (fSrcInvert)
+        cbSrcPitch = -cbSrcPitch;
+
+    crFbBltMem(pu8Src, cbSrcPitch, pu8Dst, cbDstPitch, pCopyRect->xRight - pCopyRect->xLeft, pCopyRect->yBottom - pCopyRect->yTop);
+}
+
+int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPoint, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+    VBOXVR_LIST List;
+    uint32_t c2DRects = 0;
+    CR_TEXDATA *pEnteredTex = NULL;
+    VBoxVrListInit(&List);
+    int rc = VBoxVrListRectsAdd(&List, 1, CrVrScrCompositorRectGet(&hFb->Compositor), NULL);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("VBoxVrListRectsAdd failed rc %d", rc));
+        goto end;
+    }
+
+    VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
+
+    CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter);
+
+    for(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrVrScrCompositorConstIterNext(&Iter);
+            pEntry;
+            pEntry = CrVrScrCompositorConstIterNext(&Iter))
+    {
+        uint32_t cRegions;
+        const RTRECT *pRegions;
+        rc = CrVrScrCompositorEntryRegionsGet(&hFb->Compositor, pEntry, &cRegions, NULL, NULL, &pRegions);
+        if (!RT_SUCCESS(rc))
+        {
+            WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc));
+            goto end;
+        }
+
+        rc = VBoxVrListRectsSubst(&List, cRegions, pRegions, NULL);
+        if (!RT_SUCCESS(rc))
+        {
+            WARN(("VBoxVrListRectsSubst failed rc %d", rc));
+            goto end;
+        }
+
+        Assert(!pEnteredTex);
+
+        for (uint32_t i = 0; i < cRects; ++i)
+        {
+            const RTRECT * pRect = &pRects[i];
+            for (uint32_t j = 0; j < cRegions; ++j)
+            {
+                const RTRECT * pReg = &pRegions[j];
+                RTRECT Intersection;
+                VBoxRectIntersected(pRect, pReg, &Intersection);
+                if (VBoxRectIsZero(&Intersection))
+                    continue;
+
+                CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
+                const CR_BLITTER_IMG *pSrcImg;
+
+                if (!pEnteredTex)
+                {
+                    rc = CrTdBltEnter(pTex);
+                    if (!RT_SUCCESS(rc))
+                    {
+                        WARN(("CrTdBltEnter failed %d", rc));
+                        goto end;
+                    }
+
+                    pEnteredTex = pTex;
+                }
+
+                rc = CrTdBltDataAcquire(pTex, GL_BGRA, false, &pSrcImg);
+                if (!RT_SUCCESS(rc))
+                {
+                    WARN(("CrTdBltDataAcquire failed rc %d", rc));
+                    goto end;
+                }
+
+                const RTRECT *pEntryRect = CrVrScrCompositorEntryRectGet(pEntry);
+                bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS);
+
+                crFbBltImg(pSrcImg->pvData, pEntryRect, fInvert, &Intersection, pPoint, pImg);
+
+                CrTdBltDataRelease(pTex);
+            }
+        }
+
+        if (pEnteredTex)
+        {
+            CrTdBltLeave(pEnteredTex);
+            pEnteredTex = NULL;
+        }
+    }
+
+    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};
+
+        for (uint32_t i = 0; i < cRects; ++i)
+        {
+            const RTRECT * pRect = &pRects[i];
+            for (uint32_t j = 0; j < c2DRects; ++j)
+            {
+                const RTRECT * p2DRect = &p2DRects[j];
+                RTRECT Intersection;
+                VBoxRectIntersected(pRect, p2DRect, &Intersection);
+                if (VBoxRectIsZero(&Intersection))
+                    continue;
+
+                crFbBltImg(hFb->pvVram, CrVrScrCompositorRectGet(&hFb->Compositor), false, &Intersection, pPoint, pImg);
+            }
+        }
+    }
+
+end:
+
+    if (pEnteredTex)
+        CrTdBltLeave(pEnteredTex);
+
+    VBoxVrListClear(&List);
+
+    return rc;
 }
 
@@ -464,4 +658,8 @@
         if (pFb->pDisplay)
             pFb->pDisplay->EntryDestroyed(pFb, pEntry);
+
+        CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry);
+        if (pTex)
+            CrTdBltDataDiscardNe(pTex);
     }
 }
@@ -507,4 +705,8 @@
             pFb->pDisplay->EntryReplaced(pFb, pFbReplacingEntry, pFbEntry);
 
+        CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry);
+        if (pTex)
+            CrTdBltDataDiscardNe(pTex);
+
         /* 2. mark the replaced entry is destroyed */
         Assert(pFbEntry->Flags.fCreateNotified);
@@ -522,4 +724,8 @@
             if (pFb->pDisplay)
                 pFb->pDisplay->EntryRemoved(pFb, pFbEntry);
+
+            CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry);
+            if (pTex)
+                CrTdBltDataDiscardNe(pTex);
         }
     }
@@ -582,4 +788,8 @@
         if (pFb->pDisplay)
             pFb->pDisplay->EntryTexChanged(pFb, pEntry);
+
+        CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry);
+        if (pTex)
+            CrTdBltDataDiscardNe(pTex);
     }
 
@@ -718,4 +928,8 @@
                 if (pFb->pDisplay)
                     pFb->pDisplay->EntryTexChanged(pFb, hEntry);
+
+                CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry);
+                if (pTex)
+                    CrTdBltDataDiscardNe(pTex);
             }
         }
@@ -788,4 +1002,8 @@
                 if (pFb->pDisplay)
                     pFb->pDisplay->EntryTexChanged(pFb, hEntry);
+
+                CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry);
+                if (pTex)
+                    CrTdBltDataDiscardNe(pTex);
             }
         }
@@ -3070,4 +3288,10 @@
     crFreeHashtable(g_CrPresenter.pFbTexMap, NULL);
 
+    if (g_CrPresenter.pvTmpBuf)
+        RTMemFree(g_CrPresenter.pvTmpBuf);
+
+    if (g_CrPresenter.pvTmpBuf2)
+        RTMemFree(g_CrPresenter.pvTmpBuf2);
+
     memset(&g_CrPresenter, 0, sizeof (g_CrPresenter));
 }
@@ -3084,5 +3308,5 @@
     {
         CrFbInit(&g_CrPresenter.aFramebuffers[idScreen], idScreen);
-        CrFBmSet(&g_CrPresenter.FramebufferInitMap, idScreen);
+        CrFBmSetAtomic(&g_CrPresenter.FramebufferInitMap, idScreen);
     }
     else
@@ -3903,2 +4127,154 @@
         CrFbEntryRelease(hFb, hEntry);
 }
+
+DECLINLINE(void) crVBoxPRectUnpack(const VBOXCMDVBVA_RECT *pVbvaRect, RTRECT *pRect)
+{
+    pRect->xLeft = pVbvaRect->xLeft;
+    pRect->yTop = pVbvaRect->yTop;
+    pRect->xRight = pVbvaRect->xRight;
+    pRect->yBottom = pVbvaRect->yBottom;
+}
+
+DECLINLINE(void) crVBoxPRectUnpacks(const VBOXCMDVBVA_RECT *paVbvaRects, RTRECT *paRects, uint32_t cRects)
+{
+    uint32_t i = 0;
+    for (; i < cRects; ++i)
+    {
+        crVBoxPRectUnpack(&paVbvaRects[i], &paRects[i]);
+    }
+}
+
+int32_t crVBoxServerCrCmdBltProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd)
+{
+    uint8_t u8Flags = pCmd->u8Flags;
+    if (u8Flags & (VBOXCMDVBVA_OPF_ALLOC_DSTPRIMARY | VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY))
+    {
+        VBOXCMDVBVA_BLT_PRIMARY *pBlt = (VBOXCMDVBVA_BLT_PRIMARY*)pCmd;
+        uint8_t u8PrimaryID = pBlt->Hdr.u8PrimaryID;
+        HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u8PrimaryID);
+        if (!hFb)
+        {
+            WARN(("request to present on disabled framebuffer, ignore"));
+            pCmd->i8Result = -1;
+            return VINF_SUCCESS;
+        }
+
+        const VBOXCMDVBVA_RECT *pPRects = pBlt->aRects;
+        uint32_t cRects = (cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) / sizeof (VBOXCMDVBVA_RECT);
+        RTRECT *pRects;
+        if (g_CrPresenter.cbTmpBuf < cRects * sizeof (RTRECT))
+        {
+            if (g_CrPresenter.pvTmpBuf)
+                RTMemFree(g_CrPresenter.pvTmpBuf);
+
+            g_CrPresenter.cbTmpBuf = (cRects + 10) * sizeof (RTRECT);
+            g_CrPresenter.pvTmpBuf = RTMemAlloc(g_CrPresenter.cbTmpBuf);
+            if (!g_CrPresenter.pvTmpBuf)
+            {
+                WARN(("RTMemAlloc failed!"));
+                g_CrPresenter.cbTmpBuf = 0;
+                pCmd->i8Result = -1;
+                return VINF_SUCCESS;
+            }
+        }
+
+        pRects = (RTRECT *)g_CrPresenter.pvTmpBuf;
+
+        crVBoxPRectUnpacks(pPRects, pRects, cRects);
+
+        Assert(!((cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) % sizeof (VBOXCMDVBVA_RECT)));
+
+        if (u8Flags & VBOXCMDVBVA_OPF_ALLOC_DSTPRIMARY)
+        {
+            if (!(u8Flags & VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY))
+            {
+                /* blit to primary from non-primary */
+                uint32_t texId;
+                if (u8Flags & VBOXCMDVBVA_OPF_ALLOC_DSTID)
+                {
+                    /* TexPresent */
+                    texId = pBlt->alloc.id;
+                }
+                else
+                {
+                    VBOXCMDVBVAOFFSET offVRAM = pBlt->alloc.offVRAM;
+                    const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+                    uint32_t cbScreen = pScreen->u32LineSize * pScreen->u32Height;
+                    if (offVRAM >= g_cbVRam
+                            || offVRAM + cbScreen >= g_cbVRam)
+                    {
+                        WARN(("invalid param"));
+                        pCmd->i8Result = -1;
+                        return VINF_SUCCESS;
+                    }
+
+                    uint8_t *pu8Buf = g_pvVRamBase + offVRAM;
+                    texId = 0;
+                    /*todo: notify VGA device to perform updates */
+                }
+
+                crServerDispatchVBoxTexPresent(texId, u8PrimaryID, pBlt->Pos.x, pBlt->Pos.y, cRects, (const GLint*)pRects);
+            }
+            else
+            {
+                /* blit from one primary to another primary, wow */
+                WARN(("not implemented"));
+                pCmd->i8Result = -1;
+                return VINF_SUCCESS;
+            }
+        }
+        else
+        {
+            Assert(u8Flags & VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY);
+            /* blit from primary to non-primary */
+            if (u8Flags & VBOXCMDVBVA_OPF_ALLOC_DSTID)
+            {
+                uint32_t texId = pBlt->alloc.id;
+                WARN(("not implemented"));
+                pCmd->i8Result = -1;
+                return VINF_SUCCESS;
+            }
+            else
+            {
+                VBOXCMDVBVAOFFSET offVRAM = pBlt->alloc.offVRAM;
+                const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+                uint32_t cbScreen = pScreen->u32LineSize * pScreen->u32Height;
+                if (offVRAM >= g_cbVRam
+                        || offVRAM + cbScreen >= g_cbVRam)
+                {
+                    WARN(("invalid param"));
+                    pCmd->i8Result = -1;
+                    return VINF_SUCCESS;
+                }
+
+                uint8_t *pu8Buf = g_pvVRamBase + offVRAM;
+
+                RTPOINT Pos = {pBlt->Pos.x, pBlt->Pos.y};
+                CR_BLITTER_IMG Img;
+                Img.pvData = pu8Buf;
+                Img.cbData = pScreen->u32LineSize * pScreen->u32Height;
+                Img.enmFormat = GL_BGRA;
+                Img.width = pScreen->u32Width;
+                Img.height = pScreen->u32Height;
+                Img.bpp = pScreen->u16BitsPerPixel;
+                Img.pitch = pScreen->u32LineSize;
+                int rc = CrFbBltGetContents(hFb, &Pos, cRects, pRects, &Img);
+                if (!RT_SUCCESS(rc))
+                {
+                    WARN(("CrFbBltGetContents failed %d", rc));
+                    pCmd->i8Result = -1;
+                    return VINF_SUCCESS;
+                }
+            }
+        }
+    }
+    else
+    {
+        WARN(("not implemented"));
+        pCmd->i8Result = -1;
+        return VINF_SUCCESS;
+    }
+
+    pCmd->i8Result = 0;
+    return VINF_SUCCESS;
+}
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 50312)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 50313)
@@ -69,4 +69,5 @@
 	$(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,) \
 	$(if $(VBOX_WITH_CROGL),VBOX_WITH_CROGL,) \
+	$(if $(VBOX_WITH_CRHGSMI),VBOX_WITH_CRHGSMI,) \
 	$(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
 	$(if $(VBOX_WITH_GUEST_PROPS_RDONLY_GUEST),VBOX_WITH_GUEST_PROPS_RDONLY_GUEST,) \
@@ -281,5 +282,7 @@
 	$(if $(VBOX_WITH_S3),VBOX_WITH_S3,) \
 	$(if $(VBOX_WITH_PCI_PASSTHROUGH),VBOX_WITH_PCI_PASSTHROUGH,) \
-	$(if $(VBOX_WITH_NAT_SERVICE),VBOX_WITH_NAT_SERVICE,)
+	$(if $(VBOX_WITH_NAT_SERVICE),VBOX_WITH_NAT_SERVICE,) \
+	$(if $(VBOX_WITH_HGCM),VBOX_WITH_CROGL,) \
+	$(if $(VBOX_WITH_CRHGSMI),VBOX_WITH_CRHGSMI,)
 ifdef VBOX_WITH_USB
  VBoxSVC_DEFS += \
Index: /trunk/src/VBox/Main/include/DisplayImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/DisplayImpl.h	(revision 50312)
+++ /trunk/src/VBox/Main/include/DisplayImpl.h	(revision 50313)
@@ -27,4 +27,8 @@
 #include <VBox/VBoxVideo.h>
 
+#ifdef VBOX_WITH_CROGL
+# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
+#endif
+
 class Console;
 struct VIDEORECCONTEXT;
@@ -174,4 +178,9 @@
 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
     void  handleCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam);
+    void  handleCrVRecScreenshot(uint32_t uScreen,
+                    uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBitsPerPixel,
+                    uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight,
+                    uint8_t *pu8BufferAddress, uint64_t u64TimeStamp);
+    void  handleVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext);
 #endif
 
@@ -274,4 +283,9 @@
 
 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
+    static DECLCALLBACK(void) displayCrVRecScreenshot(void *pvCtx, uint32_t uScreen,
+                    uint32_t x, uint32_t y, uint32_t uBitsPerPixel,
+                    uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight,
+                    uint8_t *pu8BufferAddress, uint64_t u64TimeStamp);
+    static DECLCALLBACK(void)  displayVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext);
     static DECLCALLBACK(void)  displayCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext);
 #endif
@@ -319,4 +333,9 @@
     HGCMCVSHANDLE mhCrOglSvc;
 #endif
+#ifdef VBOX_WITH_CROGL
+    CR_MAIN_INTERFACE mCrOglCallbacks;
+    volatile uint32_t mfCrOglVideoRecState;
+    CRVBOXHGCMTAKESCREENSHOT mCrOglScreenshotData;
+#endif
 
     bool vbvaFetchCmd(VBVACMDHDR **ppHdr, uint32_t *pcbCmd);
Index: /trunk/src/VBox/Main/src-client/DisplayImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 50312)
+++ /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 50313)
@@ -52,4 +52,12 @@
 # include <iprt/path.h>
 # include "VideoRec.h"
+#endif
+
+#ifdef VBOX_WITH_CROGL
+typedef enum
+{
+    CRVREC_STATE_IDLE,
+    CRVREC_STATE_SUBMITTED
+} CRVREC_STATE;
 #endif
 
@@ -137,4 +145,15 @@
     for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++)
         maVideoRecEnabled[i] = true;
+#endif
+
+#ifdef VBOX_WITH_CRHGSMI
+    mhCrOglSvc = NULL;
+#endif
+#ifdef VBOX_WITH_CROGL
+    RT_ZERO(mCrOglCallbacks);
+    mfCrOglVideoRecState = CRVREC_STATE_IDLE;
+    mCrOglScreenshotData.u32Screen = CRSCREEN_ALL;
+    mCrOglScreenshotData.pvContext = this;
+    mCrOglScreenshotData.pfnScreenshot = displayCrVRecScreenshot;
 #endif
 
@@ -3403,6 +3422,6 @@
         Assert(mhCrOglSvc);
         /* setup command completion callback */
-        VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION Completion;
-        Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION;
+        VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB Completion;
+        Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB;
         Completion.Hdr.cbCmd = sizeof (Completion);
         Completion.hCompletion = mpDrv->pVBVACallbacks;
@@ -3428,4 +3447,6 @@
                 pFb->pendingViewportInfo.fPending = false;
             }
+
+            mCrOglCallbacks = Completion.MainInterface;
 
             return;
@@ -3654,38 +3675,81 @@
     if (VideoRecIsEnabled(pDisplay->mpVideoRecCtx))
     {
-        uint64_t u64Now = RTTimeProgramMilliTS();
-        for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
-        {
-            if (!pDisplay->maVideoRecEnabled[uScreenId])
-                continue;
-
-            DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
-
-            if (   !pFBInfo->pFramebuffer.isNull()
-                && !pFBInfo->fDisabled
-                && pFBInfo->u32ResizeStatus == ResizeStatus_Void)
+        do {
+#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
+            BOOL is3denabled;
+            pDisplay->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
+            if (is3denabled)
             {
-                int rc;
-                if (   pFBInfo->fVBVAEnabled
-                    && pFBInfo->pu8FramebufferVRAM)
+                if (ASMAtomicCmpXchgU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_SUBMITTED, CRVREC_STATE_IDLE))
                 {
-                    rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
-                                              FramebufferPixelFormat_FOURCC_RGB,
-                                              pFBInfo->u16BitsPerPixel,
-                                              pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h,
-                                              pFBInfo->pu8FramebufferVRAM, u64Now);
+                    if (pDisplay->mCrOglCallbacks.pfnHasData())
+                    {
+                        /* submit */
+
+                        VBOXHGCMSVCPARM parm;
+
+                        parm.type = VBOX_HGCM_SVC_PARM_PTR;
+                        parm.u.pointer.addr = &pDisplay->mCrOglScreenshotData;
+                        parm.u.pointer.size = sizeof (pDisplay->mCrOglScreenshotData);
+
+                        VMMDev *pVMMDev = pDisplay->mParent->getVMMDev();
+                        if (pVMMDev)
+                        {
+                            int rc = pVMMDev->hgcmHostFastCallAsync(pDisplay->mhCrOglSvc, SHCRGL_HOST_FN_TAKE_SCREENSHOT, &parm, displayVRecCompletion, pDisplay);
+                            if (RT_SUCCESS(rc))
+                                break;
+                            else
+                                AssertMsgFailed(("hgcmHostFastCallAsync failed %f\n", rc));
+                        }
+                        else
+                            AssertMsgFailed(("no VMMDev\n"));
+                    }
+
+                    /* no 3D data available, or error has occured,
+                     * go the straight way */
+                    ASMAtomicWriteU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_IDLE);
                 }
                 else
                 {
-                    rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
-                                              FramebufferPixelFormat_FOURCC_RGB,
-                                              pDrv->IConnector.cBits,
-                                              pDrv->IConnector.cbScanline, pDrv->IConnector.cx,
-                                              pDrv->IConnector.cy, pDrv->IConnector.pu8Data, u64Now);
+                    /* record request is still in progress, don't do anything */
+                    break;
                 }
-                if (rc == VINF_TRY_AGAIN)
-                    break;
             }
-        }
+#endif
+            uint64_t u64Now = RTTimeProgramMilliTS();
+            for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
+            {
+                if (!pDisplay->maVideoRecEnabled[uScreenId])
+                    continue;
+
+                DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
+
+                if (   !pFBInfo->pFramebuffer.isNull()
+                    && !pFBInfo->fDisabled
+                    && pFBInfo->u32ResizeStatus == ResizeStatus_Void)
+                {
+                    int rc;
+                    if (   pFBInfo->fVBVAEnabled
+                        && pFBInfo->pu8FramebufferVRAM)
+                    {
+                        rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
+                                                  FramebufferPixelFormat_FOURCC_RGB,
+                                                  pFBInfo->u16BitsPerPixel,
+                                                  pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h,
+                                                  pFBInfo->pu8FramebufferVRAM, u64Now);
+                    }
+                    else
+                    {
+                        rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
+                                                  FramebufferPixelFormat_FOURCC_RGB,
+                                                  pDrv->IConnector.cBits,
+                                                  pDrv->IConnector.cbScanline, pDrv->IConnector.cx,
+                                                  pDrv->IConnector.cy, pDrv->IConnector.pu8Data, u64Now);
+                    }
+                    if (rc == VINF_TRY_AGAIN)
+                        break;
+                }
+            }
+        } while (0);
     }
 #endif
@@ -4139,4 +4203,43 @@
     if (pParam->type == VBOX_HGCM_SVC_PARM_PTR && pParam->u.pointer.addr)
         RTMemFree(pParam->u.pointer.addr);
+}
+
+
+void  Display::handleCrVRecScreenshot(uint32_t uScreen,
+                uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBitsPerPixel,
+                uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight,
+                uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)
+{
+    Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
+    int rc = VideoRecCopyToIntBuf(mpVideoRecCtx, uScreen, x, y,
+                              uPixelFormat,
+                              uBitsPerPixel, uBytesPerLine,
+                              uGuestWidth, uGuestHeight,
+                              pu8BufferAddress, u64TimeStamp);
+    Assert(rc == VINF_SUCCESS || rc == VERR_TRY_AGAIN || rc == VINF_TRY_AGAIN);
+}
+
+void  Display::handleVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext)
+{
+    Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
+    ASMAtomicWriteU32(&mfCrOglVideoRecState, CRVREC_STATE_IDLE);
+}
+
+DECLCALLBACK(void) Display::displayCrVRecScreenshot(void *pvCtx, uint32_t uScreen,
+                uint32_t x, uint32_t y, uint32_t uBitsPerPixel,
+                uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight,
+                uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)
+{
+    Display *pDisplay = (Display *)pvCtx;
+    pDisplay->handleCrVRecScreenshot(uScreen,
+            x, y, FramebufferPixelFormat_FOURCC_RGB, uBitsPerPixel,
+            uBytesPerLine, uGuestWidth, uGuestHeight,
+            pu8BufferAddress, u64TimeStamp);
+}
+
+DECLCALLBACK(void)  Display::displayVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext)
+{
+    Display *pDisplay = (Display *)pvContext;
+    pDisplay->handleVRecCompletion(result, u32Function, pParam, pvContext);
 }
 
Index: /trunk/src/VBox/Main/src-client/VideoRec.h
===================================================================
--- /trunk/src/VBox/Main/src-client/VideoRec.h	(revision 50312)
+++ /trunk/src/VBox/Main/src-client/VideoRec.h	(revision 50313)
@@ -32,5 +32,5 @@
 int  VideoRecCopyToIntBuf(PVIDEORECCONTEXT pCtx, uint32_t uScreen,
                           uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBitsPerPixel,
-                          uint32_t uBytesPerLine, uint32_t uGuestHeight, uint32_t uGuestWidth,
+                          uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight,
                           uint8_t *pu8BufferAddress, uint64_t u64TimeStamp);
 
