Index: /trunk/include/VBox/HostServices/VBoxCrOpenGLSvc.h
===================================================================
--- /trunk/include/VBox/HostServices/VBoxCrOpenGLSvc.h	(revision 50363)
+++ /trunk/include/VBox/HostServices/VBoxCrOpenGLSvc.h	(revision 50364)
@@ -396,4 +396,8 @@
     /* screen id or CRSCREEN_ALL to specify all enabled */
     uint32_t u32Screen;
+    uint32_t u32Width;
+    uint32_t u32Height;
+    uint32_t u32Pitch;
+    void *pvBuffer;
     void *pvContext;
     PFNCRSCREENSHOTBEGIN pfnScreenshotBegin;
Index: /trunk/src/VBox/GuestHost/OpenGL/Makefile.kmk
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/Makefile.kmk	(revision 50363)
+++ /trunk/src/VBox/GuestHost/OpenGL/Makefile.kmk	(revision 50364)
@@ -87,4 +87,5 @@
 	util/compositor.cpp \
 	util/htable.cpp \
+	util/bmpscale.cpp \
 	util/vboxhgcm.c \
 	$(VBOX_PATH_CROGL_GENFILES)/debug_opcodes.c
Index: /trunk/src/VBox/GuestHost/OpenGL/include/cr_blitter.h
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/include/cr_blitter.h	(revision 50363)
+++ /trunk/src/VBox/GuestHost/OpenGL/include/cr_blitter.h	(revision 50364)
@@ -80,6 +80,5 @@
         uint32_t ForceDrawBlit       : 1;
         uint32_t ShadersGloal        : 1;
-        uint32_t Entered             : 1;
-        uint32_t Reserved            : 23;
+        uint32_t Reserved            : 24;
     };
     uint32_t Value;
@@ -122,4 +121,5 @@
     GLuint idFBO;
     CR_BLITTER_FLAGS Flags;
+    uint32_t cEnters;
     PFNCRBLT_BLITTER pfnBlt;
     CR_BLITTER_BUFFER Verticies;
@@ -152,5 +152,5 @@
 DECLINLINE(GLboolean) CrBltIsEntered(PCR_BLITTER pBlitter)
 {
-    return pBlitter->Flags.Entered;
+    return !!pBlitter->cEnters;
 }
 
@@ -198,8 +198,9 @@
     struct
     {
+        uint32_t DataValid           : 1;
+        uint32_t DataAcquired        : 1;
         uint32_t DataInverted        : 1;
         uint32_t Entered             : 1;
-        uint32_t BltEntered          : 1;
-        uint32_t Reserved            : 29;
+        uint32_t Reserved            : 28;
     };
     uint32_t Value;
@@ -219,4 +220,5 @@
     /*dtor*/
     PFNCRTEXDATA_RELEASED pfnTextureReleased;
+    struct CR_TEXDATA *pStretchedCache;
 } CR_TEXDATA, *PCR_TEXDATA;
 
@@ -235,18 +237,20 @@
 }
 
+DECLINLINE(PCR_BLITTER) CrTdBlitterGet(CR_TEXDATA *pTex)
+{
+    return pTex->pBlitter;
+}
+
 DECLINLINE(int) CrTdBltEnter(PCR_TEXDATA pTex)
 {
+    int rc;
 	if (pTex->Flags.Entered)
 		return VERR_INVALID_STATE;
-	if (!CrBltIsEntered(pTex->pBlitter))
-	{
-		int rc = CrBltEnter(pTex->pBlitter);
-		if (!RT_SUCCESS(rc))
-		{
-			WARN(("CrBltEnter failed rc %d", rc));
-			return rc;
-		}
-		pTex->Flags.BltEntered = 1;
-	}
+	rc = CrBltEnter(pTex->pBlitter);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("CrBltEnter failed rc %d", rc));
+        return rc;
+    }
 	pTex->Flags.Entered = 1;
 	return VINF_SUCCESS;
@@ -266,9 +270,5 @@
 	}
 
-	if (pTex->Flags.BltEntered)
-	{
-		CrBltLeave(pTex->pBlitter);
-		pTex->Flags.BltEntered = 0;
-	}
+	CrBltLeave(pTex->pBlitter);
 
 	pTex->Flags.Entered = 0;
@@ -277,14 +277,22 @@
 /* the CrTdBltXxx calls are done with the entered blitter */
 /* acquire the texture data, returns the cached data in case it is cached.
- * the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataDiscard or CrTdBltDataCleanup.
+ * the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataFree or CrTdBltDataCleanup.
  * */
 VBOXBLITTERDECL(int) CrTdBltDataAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, const CR_BLITTER_IMG**ppImg);
-/* release the texture data, the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataDiscard or CrTdBltDataCleanup */
+
+VBOXBLITTERDECL(int) CrTdBltDataAcquireStretched(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, uint32_t width, uint32_t height, const CR_BLITTER_IMG**ppImg);
+
+VBOXBLITTERDECL(int) CrTdBltDataReleaseStretched(PCR_TEXDATA pTex, const CR_BLITTER_IMG *pImg);
+
+VBOXBLITTERDECL(void) CrTdBltStretchCacheMoveTo(PCR_TEXDATA pTex, PCR_TEXDATA pDstTex);
+
+/* release the texture data, the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataFree or CrTdBltDataCleanup */
 VBOXBLITTERDECL(int) CrTdBltDataRelease(PCR_TEXDATA pTex);
 /* discard the texture data cached with previous CrTdBltDataAcquire.
  * 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.
+VBOXBLITTERDECL(int) CrTdBltDataFree(PCR_TEXDATA pTex);
+VBOXBLITTERDECL(int) CrTdBltDataFreeNe(PCR_TEXDATA pTex);
+VBOXBLITTERDECL(void) CrTdBltDataInvalidateNe(PCR_TEXDATA pTex);
+/* does same as CrTdBltDataFree, 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 */
 VBOXBLITTERDECL(int) CrTdBltDataCleanup(PCR_TEXDATA pTex);
Index: /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h	(revision 50363)
+++ /trunk/src/VBox/GuestHost/OpenGL/include/cr_server.h	(revision 50364)
@@ -523,8 +523,8 @@
     CR_BLITTER_IMG Img;
     uint32_t u32Screen;
-    uint32_t fDataIsFbDirect;
+    uint32_t fDataAllocated;
 } CR_SCREENSHOT;
 
-extern DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, CR_SCREENSHOT *pScreenshot);
+extern DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, uint32_t width, uint32_t height, uint32_t pitch, void *pvBuffer, CR_SCREENSHOT *pScreenshot);
 extern DECLEXPORT(void) crServerVBoxScreenshotRelease(CR_SCREENSHOT *pScreenshot);
 
Index: /trunk/src/VBox/GuestHost/OpenGL/util/blitter.cpp
===================================================================
--- /trunk/src/VBox/GuestHost/OpenGL/util/blitter.cpp	(revision 50363)
+++ /trunk/src/VBox/GuestHost/OpenGL/util/blitter.cpp	(revision 50364)
@@ -98,5 +98,5 @@
     if (CrBltIsEntered(pBlitter))
     {
-        crWarning("CrBltBlitTexTex: blitter is entered");
+        WARN(("CrBltBlitTexTex: blitter is entered"));
         return VERR_INVALID_STATE;
     }
@@ -108,5 +108,5 @@
     if (!RT_SUCCESS(rc))
     {
-        crWarning("CrBltEnter failed, rc %d", rc);
+        WARN(("CrBltEnter failed, rc %d", rc));
         return rc;
     }
@@ -138,5 +138,5 @@
         if (CrBltIsEntered(pBlitter))
         {
-            crWarning("can not set null mural for entered bleater");
+            WARN(("can not set null mural for entered bleater"));
             return VERR_INVALID_STATE;
         }
@@ -152,9 +152,9 @@
     else if (!pBlitter->CtxInfo.Base.id)
     {
-        crWarning("setting current mural for entered no-context blitter");
+        WARN(("setting current mural for entered no-context blitter"));
         return VERR_INVALID_STATE;
     }
 
-    crWarning("changing mural for entered blitter, is is somewhat expected?");
+    WARN(("changing mural for entered blitter, is is somewhat expected?"));
 
     pBlitter->pDispatch->Flush();
@@ -548,9 +548,12 @@
 void CrBltLeave(PCR_BLITTER pBlitter)
 {
-    if (!CrBltIsEntered(pBlitter))
-    {
-        WARN(("CrBltLeave: blitter not entered"));
+    if (!pBlitter->cEnters)
+    {
+        WARN(("blitter not entered!"));
         return;
     }
+
+    if (--pBlitter->cEnters)
+        return;
 
     if (pBlitter->Flags.SupportsFBO)
@@ -565,6 +568,4 @@
     if (pBlitter->CtxInfo.Base.id)
         pBlitter->pDispatch->MakeCurrent(0, 0, 0);
-
-    pBlitter->Flags.Entered = 0;
 }
 
@@ -577,9 +578,6 @@
     }
 
-    if (CrBltIsEntered(pBlitter))
-    {
-        WARN(("blitter is entered already!"));
-        return VERR_INVALID_STATE;
-    }
+    if (pBlitter->cEnters++)
+        return VINF_SUCCESS;
 
     if (pBlitter->CurrentMural.Base.id) /* <- pBlitter->CurrentMural.Base.id can be null if the blitter is in a "no-context" mode (see comments to BltInit for detail)*/
@@ -587,6 +585,4 @@
         pBlitter->pDispatch->MakeCurrent(pBlitter->CurrentMural.Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id);
     }
-
-    pBlitter->Flags.Entered = 1;
 
     if (pBlitter->Flags.Initialized)
@@ -647,5 +643,5 @@
     if (!CrBltIsEntered(pBlitter))
     {
-        crWarning("CrBltBlitTexMural: blitter not entered");
+        WARN(("CrBltBlitTexMural: blitter not entered"));
         return;
     }
@@ -662,5 +658,5 @@
     if (!CrBltIsEntered(pBlitter))
     {
-        crWarning("CrBltBlitTexTex: blitter not entered");
+        WARN(("CrBltBlitTexTex: blitter not entered"));
         return;
     }
@@ -686,5 +682,5 @@
     if (!CrBltIsEntered(pBlitter))
     {
-        crWarning("CrBltPresent: blitter not entered");
+        WARN(("CrBltPresent: blitter not entered"));
         return;
     }
@@ -702,5 +698,5 @@
             && enmFormat != GL_BGRA)
     {
-        crWarning("unsupported format 0x%x", enmFormat);
+        WARN(("unsupported format 0x%x", enmFormat));
         return VERR_NOT_IMPLEMENTED;
     }
@@ -752,5 +748,5 @@
     if (!CrBltIsEntered(pBlitter))
     {
-        crWarning("CrBltImgGetTex: blitter not entered");
+        WARN(("CrBltImgGetTex: blitter not entered"));
         return VERR_INVALID_STATE;
     }
@@ -787,5 +783,5 @@
     if (!CrBltIsEntered(pBlitter))
     {
-        crWarning("CrBltImgGetMural: blitter not entered");
+        WARN(("CrBltImgGetMural: blitter not entered"));
         return VERR_INVALID_STATE;
     }
@@ -799,5 +795,5 @@
     if (!CrBltIsEntered(pBlitter))
     {
-        crWarning("CrBltImgFree: blitter not entered");
+        WARN(("CrBltImgFree: blitter not entered"));
         return;
     }
@@ -1127,5 +1123,4 @@
 
 /*TdBlt*/
-
 static void crTdBltCheckPBO(PCR_TEXDATA pTex)
 {
@@ -1152,7 +1147,6 @@
 }
 
-static uint32_t crTdBltTexCreate(PCR_TEXDATA pTex)
-{
-	PCR_BLITTER pBlitter = pTex->pBlitter;
+static uint32_t crTdBltTexCreate(PCR_BLITTER pBlitter, uint32_t width, uint32_t height, GLenum enmTarget)
+{
     uint32_t tex = 0;
     pBlitter->pDispatch->GenTextures(1, &tex);
@@ -1163,17 +1157,16 @@
     }
 
-    pBlitter->pDispatch->BindTexture(GL_TEXTURE_2D, tex);
-    pBlitter->pDispatch->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    pBlitter->pDispatch->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    pBlitter->pDispatch->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-    pBlitter->pDispatch->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-    pBlitter->pDispatch->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
-            pTex->Tex.width,
-            pTex->Tex.height,
+    pBlitter->pDispatch->BindTexture(enmTarget, tex);
+    pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_WRAP_T, GL_CLAMP);
+    pBlitter->pDispatch->TexImage2D(enmTarget, 0, GL_RGBA8,
+            width, height,
             0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
 
 
     /*Restore gl state*/
-    pBlitter->pDispatch->BindTexture(GL_TEXTURE_2D, 0);
+    pBlitter->pDispatch->BindTexture(enmTarget, 0);
 
     return tex;
@@ -1185,5 +1178,5 @@
         return VINF_SUCCESS;
 
-    pTex->idInvertTex = crTdBltTexCreate(pTex);
+    pTex->idInvertTex = crTdBltTexCreate(pTex->pBlitter, pTex->Tex.width, pTex->Tex.height, pTex->Tex.target);
     if (!pTex->idInvertTex)
     {
@@ -1194,13 +1187,26 @@
 }
 
+void crTdBltImgRelease(PCR_TEXDATA pTex)
+{
+    pTex->Flags.DataValid = 0;
+}
+
 void crTdBltImgFree(PCR_TEXDATA pTex)
 {
     if (!pTex->Img.pvData)
+    {
+        Assert(!pTex->Flags.DataValid);
         return;
-
-    PCR_BLITTER pBlitter = pTex->pBlitter;
+    }
+
+    crTdBltImgRelease(pTex);
+
+    Assert(!pTex->Flags.DataValid);
+
 
     if (pTex->idPBO)
     {
+        PCR_BLITTER pBlitter = pTex->pBlitter;
+
         Assert(CrBltIsEntered(pBlitter));
         pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
@@ -1209,5 +1215,8 @@
     }
     else
+    {
+        Assert(pTex->Img.pvData);
         RTMemFree(pTex->Img.pvData);
+    }
 
     pTex->Img.pvData = NULL;
@@ -1216,26 +1225,43 @@
 int crTdBltImgAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted)
 {
+    void *pvData = pTex->Img.pvData;
+    Assert(!pTex->Flags.DataValid);
     int rc = crBltImgInitBaseForTex(&pTex->Tex, &pTex->Img, enmFormat);
     if (!RT_SUCCESS(rc))
     {
-        crWarning("crBltImgInitBaseForTex failed rc %d", rc);
+        WARN(("crBltImgInitBaseForTex failed rc %d", rc));
         return rc;
     }
 
     PCR_BLITTER pBlitter = pTex->pBlitter;
-    void *pvData = NULL;
+    Assert(CrBltIsEntered(pBlitter));
     pBlitter->pDispatch->BindTexture(pTex->Tex.target, fInverted ? pTex->idInvertTex : pTex->Tex.hwid);
 
     pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO);
 
-    if (!pTex->idPBO)
-    {
-        pvData = RTMemAlloc(4*pTex->Tex.width*pTex->Tex.height);
-        if (!pvData)
-        {
-            crWarning("Out of memory in crTdBltImgAcquire");
-            return VERR_NO_MEMORY;
-        }
-    }
+    if (pvData)
+    {
+        if (pTex->idPBO)
+        {
+            pBlitter->pDispatch->UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
+            pvData = NULL;
+
+        }
+    }
+    else
+    {
+        if (!pTex->idPBO)
+        {
+            pvData = RTMemAlloc(4*pTex->Tex.width*pTex->Tex.height);
+            if (!pvData)
+            {
+                WARN(("Out of memory in crTdBltImgAcquire"));
+                pBlitter->pDispatch->BindTexture(pTex->Tex.target, 0);
+                return VERR_NO_MEMORY;
+            }
+        }
+    }
+
+    Assert(!pvData == !!pTex->idPBO);
 
     /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/
@@ -1250,5 +1276,5 @@
         if (!pvData)
         {
-            crWarning("Failed to MapBuffer in CrHlpGetTexImage");
+            WARN(("Failed to MapBuffer in CrHlpGetTexImage"));
             return VERR_GENERAL_FAILURE;
         }
@@ -1257,11 +1283,12 @@
     }
 
-    CRASSERT(pvData);
+    Assert(pvData);
     pTex->Img.pvData = pvData;
+    pTex->Flags.DataValid = 1;
     pTex->Flags.DataInverted = fInverted;
     return VINF_SUCCESS;
 }
 
-/* release the texture data, the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataDiscard or CrTdBltDataCleanup */
+/* release the texture data, the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataInvalidateNe or CrTdBltDataCleanup */
 VBOXBLITTERDECL(int) CrTdBltDataRelease(PCR_TEXDATA pTex)
 {
@@ -1271,11 +1298,30 @@
         return VERR_INVALID_STATE;
     }
+
+    if (!pTex->Flags.DataAcquired)
+    {
+        WARN(("Data NOT acquired"));
+        return VERR_INVALID_STATE;
+    }
+
     Assert(pTex->Img.pvData);
-    return VINF_SUCCESS;
+    Assert(pTex->Flags.DataValid);
+
+    pTex->Flags.DataAcquired = 0;
+
+    return VINF_SUCCESS;
+}
+
+static void crTdBltDataFree(PCR_TEXDATA pTex)
+{
+    crTdBltImgFree(pTex);
+
+    if (pTex->pStretchedCache)
+        CrTdBltDataFreeNe(pTex->pStretchedCache);
 }
 
 /* discard the texture data cached with previous CrTdBltDataAcquire.
  * Must be called wit data released (CrTdBltDataRelease) */
-VBOXBLITTERDECL(int) CrTdBltDataDiscard(PCR_TEXDATA pTex)
+VBOXBLITTERDECL(int) CrTdBltDataFree(PCR_TEXDATA pTex)
 {
     if (!pTex->Flags.Entered)
@@ -1285,10 +1331,18 @@
     }
 
-    crTdBltImgFree(pTex);
-
-    return VINF_SUCCESS;
-}
-
-VBOXBLITTERDECL(int) CrTdBltDataDiscardNe(PCR_TEXDATA pTex)
+    crTdBltDataFree(pTex);
+
+    return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(void) CrTdBltDataInvalidateNe(PCR_TEXDATA pTex)
+{
+    crTdBltImgRelease(pTex);
+
+    if (pTex->pStretchedCache)
+        CrTdBltDataInvalidateNe(pTex->pStretchedCache);
+}
+
+VBOXBLITTERDECL(int) CrTdBltDataFreeNe(PCR_TEXDATA pTex)
 {
     if (!pTex->Img.pvData)
@@ -1308,5 +1362,5 @@
     }
 
-    crTdBltImgFree(pTex);
+    crTdBltDataFree(pTex);
 
     if (fEntered)
@@ -1314,4 +1368,14 @@
 
     return VINF_SUCCESS;
+}
+
+static void crTdBltSdCleanupCacheNe(PCR_TEXDATA pTex)
+{
+    if (pTex->pStretchedCache)
+    {
+        CrTdBltDataCleanupNe(pTex->pStretchedCache);
+        CrTdRelease(pTex->pStretchedCache);
+        pTex->pStretchedCache = NULL;
+    }
 }
 
@@ -1335,7 +1399,9 @@
         pTex->idInvertTex = 0;
     }
-}
-
-/* does same as CrTdBltDataDiscard, and in addition cleans up */
+
+    crTdBltSdCleanupCacheNe(pTex);
+}
+
+/* does same as CrTdBltDataFree, and in addition cleans up */
 VBOXBLITTERDECL(int) CrTdBltDataCleanup(PCR_TEXDATA pTex)
 {
@@ -1375,5 +1441,5 @@
 
 /* acquire the texture data, returns the cached data in case it is cached.
- * the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataDiscard or CrTdBltDataCleanup.
+ * the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataFree or CrTdBltDataCleanup.
  * */
 VBOXBLITTERDECL(int) CrTdBltDataAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, const CR_BLITTER_IMG**ppImg)
@@ -1385,11 +1451,19 @@
     }
 
-    if (pTex->Img.pvData && pTex->Img.enmFormat == enmFormat && !pTex->Flags.DataInverted == !fInverted)
-    {
+    if (pTex->Flags.DataAcquired)
+    {
+        WARN(("Data acquired already"));
+        return VERR_INVALID_STATE;
+    }
+
+    if (pTex->Flags.DataValid && pTex->Img.enmFormat == enmFormat && !pTex->Flags.DataInverted == !fInverted)
+    {
+        Assert(pTex->Img.pvData);
         *ppImg = &pTex->Img;
+        pTex->Flags.DataAcquired = 1;
         return VINF_SUCCESS;
     }
 
-    crTdBltImgFree(pTex);
+    crTdBltImgRelease(pTex);
 
     crTdBltCheckPBO(pTex);
@@ -1432,6 +1506,246 @@
     }
 
+    Assert(pTex->Img.pvData);
     *ppImg = &pTex->Img;
-
-    return VINF_SUCCESS;
-}
+    pTex->Flags.DataAcquired = 1;
+
+    return VINF_SUCCESS;
+}
+
+DECLINLINE(void) crTdResize(PCR_TEXDATA pTex, const VBOXVR_TEXTURE *pVrTex)
+{
+    crTdBltDataCleanup(pTex);
+
+    pTex->Tex = *pVrTex;
+}
+
+static DECLCALLBACK(void) ctTdBltSdReleased(struct CR_TEXDATA *pTexture)
+{
+    PCR_BLITTER pBlitter = pTexture->pBlitter;
+
+    int rc = CrBltEnter(pBlitter);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("CrBltEnter failed, rc %d", rc));
+        return;
+    }
+
+    CrTdBltDataCleanupNe(pTexture);
+
+    pBlitter->pDispatch->DeleteTextures(1, &pTexture->Tex.hwid);
+
+    CrBltLeave(pBlitter);
+
+    RTMemFree(pTexture);
+}
+
+static int ctTdBltSdCreate(PCR_BLITTER pBlitter, uint32_t width, uint32_t height, GLenum enmTarget, PCR_TEXDATA *ppStretchedCache)
+{
+    PCR_TEXDATA pStretchedCache;
+
+    Assert(CrBltIsEntered(pBlitter));
+
+    *ppStretchedCache = NULL;
+
+    pStretchedCache = (PCR_TEXDATA)RTMemAlloc(sizeof (*pStretchedCache));
+    if (!pStretchedCache)
+    {
+        WARN(("RTMemAlloc failed"));
+        return VERR_NO_MEMORY;
+    }
+
+    VBOXVR_TEXTURE Tex;
+    Tex.width = width;
+    Tex.height = height;
+    Tex.target = enmTarget;
+    Tex.hwid = crTdBltTexCreate(pBlitter, width, height, enmTarget);
+    if (!Tex.hwid)
+    {
+        WARN(("Tex create failed"));
+        RTMemFree(pStretchedCache);
+        return VERR_GENERAL_FAILURE;
+    }
+
+    CrTdInit(pStretchedCache, &Tex, pBlitter, ctTdBltSdReleased);
+
+    *ppStretchedCache = pStretchedCache;
+
+    return VINF_SUCCESS;
+}
+
+static int ctTdBltSdGet(PCR_TEXDATA pTex, uint32_t width, uint32_t height, PCR_TEXDATA *ppStretchedCache)
+{
+    Assert(pTex->Flags.Entered);
+
+    PCR_TEXDATA pStretchedCache;
+
+    *ppStretchedCache = NULL;
+
+    if (!pTex->pStretchedCache)
+    {
+        int rc = ctTdBltSdCreate(pTex->pBlitter, width, height, pTex->Tex.target, &pStretchedCache);
+        if (!RT_SUCCESS(rc))
+        {
+            WARN(("ctTdBltSdCreate failed %d", rc));
+            return rc;
+        }
+
+        pTex->pStretchedCache = pStretchedCache;
+    }
+    else
+    {
+        int cmp = pTex->pStretchedCache->Tex.width - width;
+        if (cmp <= 0)
+            cmp = pTex->pStretchedCache->Tex.height - height;
+
+        if (!cmp)
+            pStretchedCache = pTex->pStretchedCache;
+        else if (cmp < 0) /* current cache is "less" than the requested */
+        {
+            int rc = ctTdBltSdCreate(pTex->pBlitter, width, height, pTex->Tex.target, &pStretchedCache);
+            if (!RT_SUCCESS(rc))
+            {
+                WARN(("ctTdBltSdCreate failed %d", rc));
+                return rc;
+            }
+
+            pStretchedCache->pStretchedCache = pTex->pStretchedCache;
+            pTex->pStretchedCache = pStretchedCache;
+        }
+        else /* cmp > 0 */
+        {
+            int rc = ctTdBltSdGet(pTex->pStretchedCache, width, height, &pStretchedCache);
+            if (!RT_SUCCESS(rc))
+            {
+                WARN(("ctTdBltSdGet failed %d", rc));
+                return rc;
+            }
+        }
+    }
+
+    Assert(pStretchedCache);
+
+#if 0
+    {
+        VBOXVR_TEXTURE Tex;
+        Tex.width = width;
+        Tex.height = height;
+        Tex.target = pTex->Tex.target;
+        Tex.hwid = crTdBltTexCreate(pTex, width, height);
+        if (!Tex.hwid)
+        {
+            WARN(("Tex create failed"));
+            return VERR_GENERAL_FAILURE;
+        }
+
+        pTex->pBlitter->pDispatch->DeleteTextures(1, &pTex->pStretchedCache->Tex.hwid);
+
+        crTdResize(pTex->pStretchedCache, &Tex);
+    }
+#endif
+
+    *ppStretchedCache = pStretchedCache;
+    return VINF_SUCCESS;
+}
+
+static int ctTdBltSdGetUpdated(PCR_TEXDATA pTex, uint32_t width, uint32_t height, PCR_TEXDATA *ppStretchedCache)
+{
+    PCR_TEXDATA pStretchedCache;
+
+    *ppStretchedCache = NULL;
+    int rc = ctTdBltSdGet(pTex, width, height, &pStretchedCache);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("ctTdBltSdGet failed %d", rc));
+        return rc;
+    }
+
+    Assert(width == pStretchedCache->Tex.width);
+    Assert(height == pStretchedCache->Tex.height);
+
+    if (!pStretchedCache->Flags.DataValid)
+    {
+        RTRECT SrcRect, DstRect;
+
+        SrcRect.xLeft = 0;
+        SrcRect.yTop = 0;
+        SrcRect.xRight = pTex->Tex.width;
+        SrcRect.yBottom = pTex->Tex.height;
+
+        DstRect.xLeft = 0;
+        DstRect.yTop = 0;
+        DstRect.xRight = width;
+        DstRect.yBottom = height;
+
+        CrBltBlitTexTex(pTex->pBlitter, &pTex->Tex, &SrcRect, &pStretchedCache->Tex, &DstRect, 1, 0);
+    }
+
+    *ppStretchedCache = pStretchedCache;
+
+    return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(int) CrTdBltDataAcquireStretched(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, uint32_t width, uint32_t height, const CR_BLITTER_IMG**ppImg)
+{
+    if (pTex->Tex.width == width && pTex->Tex.height == height)
+        return CrTdBltDataAcquire(pTex, enmFormat, fInverted, ppImg);
+
+    if (!pTex->Flags.Entered)
+    {
+        WARN(("tex not entered"));
+        return VERR_INVALID_STATE;
+    }
+
+    PCR_TEXDATA pStretchedCache;
+
+    int rc = ctTdBltSdGetUpdated(pTex, width, height, &pStretchedCache);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("ctTdBltSdGetUpdated failed rc %d", rc));
+        return rc;
+    }
+
+    rc = CrTdBltEnter(pStretchedCache);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("CrTdBltEnter failed rc %d", rc));
+        return rc;
+    }
+
+    rc = CrTdBltDataAcquire(pStretchedCache, enmFormat, fInverted, ppImg);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("CrTdBltDataAcquire failed rc %d", rc));
+        CrTdBltLeave(pTex->pStretchedCache);
+        return rc;
+    }
+
+    return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(int) CrTdBltDataReleaseStretched(PCR_TEXDATA pTex, const CR_BLITTER_IMG *pImg)
+{
+    PCR_TEXDATA pStretchedCache = RT_FROM_MEMBER(pImg, CR_TEXDATA, Img);
+    int rc = CrTdBltDataRelease(pStretchedCache);
+    if (!RT_SUCCESS(rc))
+    {
+        WARN(("CrTdBltDataRelease failed rc %d", rc));
+        return rc;
+    }
+
+    if (pStretchedCache != pTex)
+        CrTdBltLeave(pStretchedCache);
+
+    return VINF_SUCCESS;
+}
+
+VBOXBLITTERDECL(void) CrTdBltStretchCacheMoveTo(PCR_TEXDATA pTex, PCR_TEXDATA pDstTex)
+{
+    if (!pTex->pStretchedCache)
+        return;
+
+    crTdBltSdCleanupCacheNe(pDstTex);
+
+    pDstTex->pStretchedCache = pTex->pStretchedCache;
+    pTex->pStretchedCache = NULL;
+}
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp	(revision 50363)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp	(revision 50364)
@@ -939,11 +939,12 @@
         CR_SCREENSHOT Screenshot;
 
-        int rc = crServerVBoxScreenshotGet(idScreen, &Screenshot);
+        int rc = crServerVBoxScreenshotGet(idScreen, pScreenshot->u32Width, pScreenshot->u32Height, pScreenshot->u32Pitch, pScreenshot->pvBuffer, &Screenshot);
         if (RT_SUCCESS(rc))
         {
-            pScreenshot->pfnScreenshotPerform(pScreenshot->pvContext, idScreen,
-                    0, 0, 32,
-                    Screenshot.Img.pitch, Screenshot.Img.width, Screenshot.Img.height,
-                    (uint8_t*)Screenshot.Img.pvData, u64Now);
+            if (pScreenshot->pfnScreenshotPerform)
+                pScreenshot->pfnScreenshotPerform(pScreenshot->pvContext, idScreen,
+                        0, 0, 32,
+                        Screenshot.Img.pitch, Screenshot.Img.width, Screenshot.Img.height,
+                        (uint8_t*)Screenshot.Img.pvData, u64Now);
             crServerVBoxScreenshotRelease(&Screenshot);
         }
Index: /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h	(revision 50363)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h	(revision 50364)
@@ -425,5 +425,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 RTPOINT *pPoint, uint32_t cRects, const RTRECT *pPrects, CR_BLITTER_IMG *pImg);
+int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, 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_muralfbo.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp	(revision 50363)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp	(revision 50364)
@@ -658,5 +658,14 @@
 }
 
-DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, CR_SCREENSHOT *pScreenshot)
+DECLEXPORT(void) crServerVBoxScreenshotRelease(CR_SCREENSHOT *pScreenshot)
+{
+    if (pScreenshot->fDataAllocated)
+    {
+        RTMemFree(pScreenshot->Img.pvData);
+        pScreenshot->fDataAllocated = 0;
+    }
+}
+
+DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, uint32_t width, uint32_t height, uint32_t pitch, void *pvBuffer, CR_SCREENSHOT *pScreenshot)
 {
     HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32Screen);
@@ -666,15 +675,62 @@
     const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
 
-    if (CrFbHas3DData(hFb))
-    {
-        RTPOINT Pos = {0, 0};
+    if (!width)
+        width = pScreen->u32Width;
+    if (!height)
+        height = pScreen->u32Height;
+    if (!pitch)
+        pitch = pScreen->u32LineSize;
+
+    if (CrFbHas3DData(hFb)
+            || pScreen->u32Width != width
+            || pScreen->u32Height != height
+            || pScreen->u32LineSize != pitch
+            || pScreen->u16BitsPerPixel != 32)
+    {
         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;
+        if (!pvBuffer)
+        {
+            pScreenshot->Img.pvData = RTMemAlloc(pScreenshot->Img.cbData);
+            if (!pScreenshot->Img.pvData)
+            {
+                WARN(("RTMemAlloc failed"));
+                return VERR_NO_MEMORY;
+            }
+            pScreenshot->fDataAllocated = 1;
+        }
+        else
+        {
+            pScreenshot->Img.pvData = pvBuffer;
+            pScreenshot->fDataAllocated = 0;
+        }
+
+        pScreenshot->Img.enmFormat = GL_BGRA;
+        pScreenshot->Img.width = width;
+        pScreenshot->Img.height = height;
+        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);
+        if (!RT_SUCCESS(rc))
+        {
+            WARN(("CrFbBltGetContents failed %d", rc));
+            crServerVBoxScreenshotRelease(pScreenshot);
+            return rc;
+        }
+    }
+    else
+    {
+        pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height;
+        if (!pvBuffer)
+            pScreenshot->Img.pvData = CrFbGetVRAM(hFb);
+        else
+        {
+            pScreenshot->Img.pvData = pvBuffer;
+            memcpy(pvBuffer, CrFbGetVRAM(hFb), pScreenshot->Img.cbData);
         }
         pScreenshot->Img.enmFormat = GL_BGRA;
@@ -683,28 +739,6 @@
         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->fDataAllocated = 0;
     }
 
@@ -712,13 +746,4 @@
 
     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 50363)
+++ /trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp	(revision 50364)
@@ -27,4 +27,5 @@
 #include <cr_vreg.h>
 #include <cr_htable.h>
+#include <cr_bmpscale.h>
 
 #include <iprt/cdefs.h>
@@ -83,4 +84,34 @@
     CRHTABLE SlotTable;
 } CR_FRAMEBUFFER;
+
+typedef union CR_FBENTRY_FLAGS
+{
+    struct {
+        uint32_t fCreateNotified : 1;
+        uint32_t fInList         : 1;
+        uint32_t Reserved        : 30;
+    };
+    uint32_t Value;
+} CR_FBENTRY_FLAGS;
+
+typedef struct CR_FRAMEBUFFER_ENTRY
+{
+    VBOXVR_SCR_COMPOSITOR_ENTRY Entry;
+    RTLISTNODE Node;
+    uint32_t cRefs;
+    CR_FBENTRY_FLAGS Flags;
+    CRHTABLE HTable;
+} CR_FRAMEBUFFER_ENTRY;
+
+typedef struct CR_FBTEX
+{
+    CR_TEXDATA Tex;
+    CRTextureObj *pTobj;
+} CR_FBTEX;
+
+#define PCR_FBTEX_FROM_TEX(_pTex) ((CR_FBTEX*)((uint8_t*)(_pTex) - RT_OFFSETOF(CR_FBTEX, Tex)))
+#define PCR_FRAMEBUFFER_FROM_COMPOSITOR(_pCompositor) ((CR_FRAMEBUFFER*)((uint8_t*)(_pCompositor) - RT_OFFSETOF(CR_FRAMEBUFFER, Compositor)))
+#define PCR_FBENTRY_FROM_ENTRY(_pEntry) ((CR_FRAMEBUFFER_ENTRY*)((uint8_t*)(_pEntry) - RT_OFFSETOF(CR_FRAMEBUFFER_ENTRY, Entry)))
+
 
 typedef struct CR_FBDISPLAY_INFO
@@ -234,9 +265,50 @@
 }
 
-int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPoint, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+static void crFbBltImgStretched(void *pvSrc, const RTRECT *pSrcDataRect, bool fSrcInvert, const RTRECT *pCopyRect, const RTPOINT *pDstDataPoint, float strX, float strY, 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);
+
+    int32_t cbDstPitch = (int32_t)pDst->pitch;
+    int32_t dstX = static_cast<uint32_t>(strX * pCopyRect->xLeft - pDstDataPoint->x);
+    int32_t dstY = static_cast<uint32_t>(strY * 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;
+
+    int srcW = pCopyRect->xRight - pCopyRect->xLeft;
+    int srcH = pCopyRect->yBottom - pCopyRect->yTop;
+    int dstW = static_cast<uint32_t>(strX * srcW);
+    int dstH = static_cast<uint32_t>(strY * srcH);
+
+    CrBmpScale32(pu8Dst, cbDstPitch,
+                            dstW, dstH,
+                            pu8Src,
+                            cbSrcPitch,
+                            srcW, srcH);
+}
+
+
+static int crFbBltGetContentsDirect(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
 {
     VBOXVR_LIST List;
     uint32_t c2DRects = 0;
     CR_TEXDATA *pEnteredTex = NULL;
+    PCR_BLITTER pEnteredBlitter = NULL;
+
+    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);
+
     VBoxVrListInit(&List);
     int rc = VBoxVrListRectsAdd(&List, 1, CrVrScrCompositorRectGet(&hFb->Compositor), NULL);
@@ -247,6 +319,4 @@
     }
 
-    VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
-
     CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter);
 
@@ -271,5 +341,6 @@
         }
 
-        Assert(!pEnteredTex);
+        uint32_t width, height;
+        RTRECT SrcRect;
 
         for (uint32_t i = 0; i < cRects; ++i)
@@ -284,9 +355,47 @@
                     continue;
 
+                VBoxRectStretch(&Intersection, strX, strY);
+                if (VBoxRectIsZero(&Intersection))
+                    continue;
+
                 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
                 const CR_BLITTER_IMG *pSrcImg;
 
-                if (!pEnteredTex)
+                if (pEnteredTex != pTex)
                 {
+                    if (!pEnteredBlitter)
+                    {
+                        pEnteredBlitter = CrTdBlitterGet(pTex);
+                        rc = CrBltEnter(pEnteredBlitter);
+                        if (!RT_SUCCESS(rc))
+                        {
+                            WARN(("CrBltEnter failed %d", rc));
+                            pEnteredBlitter = NULL;
+                            goto end;
+                        }
+                    }
+
+                    if (pEnteredTex)
+                    {
+                        CrTdBltLeave(pEnteredTex);
+
+                        pEnteredTex = NULL;
+
+                        if (pEnteredBlitter != CrTdBlitterGet(pTex))
+                        {
+                            WARN(("blitters not equal!"));
+                            CrBltLeave(pEnteredBlitter);
+
+                            pEnteredBlitter = CrTdBlitterGet(pTex);
+                            rc = CrBltEnter(pEnteredBlitter);
+                             if (!RT_SUCCESS(rc))
+                             {
+                                 WARN(("CrBltEnter failed %d", rc));
+                                 pEnteredBlitter = NULL;
+                                 goto end;
+                             }
+                        }
+                    }
+
                     rc = CrTdBltEnter(pTex);
                     if (!RT_SUCCESS(rc))
@@ -297,7 +406,13 @@
 
                     pEnteredTex = pTex;
+
+                    const VBOXVR_TEXTURE *pVrTex = CrTdTexGet(pTex);
+
+                    width = static_cast<uint32_t>(strX * pVrTex->width);
+                    height = static_cast<uint32_t>(strY * pVrTex->height);
+                    VBoxRectStretched(CrVrScrCompositorEntryRectGet(pEntry), strX, strY, &SrcRect);
                 }
 
-                rc = CrTdBltDataAcquire(pTex, GL_BGRA, false, &pSrcImg);
+                rc = CrTdBltDataAcquireStretched(pTex, GL_BGRA, false, width, height, &pSrcImg);
                 if (!RT_SUCCESS(rc))
                 {
@@ -306,17 +421,10 @@
                 }
 
-                const RTRECT *pEntryRect = CrVrScrCompositorEntryRectGet(pEntry);
                 bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS);
 
-                crFbBltImg(pSrcImg->pvData, pEntryRect, fInvert, &Intersection, pPoint, pImg);
-
-                CrTdBltDataRelease(pTex);
+                crFbBltImg(pSrcImg->pvData, &SrcRect, fInvert, &Intersection, &SrcPoint, pImg);
+
+                CrTdBltDataReleaseStretched(pTex, pSrcImg);
             }
-        }
-
-        if (pEnteredTex)
-        {
-            CrTdBltLeave(pEnteredTex);
-            pEnteredTex = NULL;
         }
     }
@@ -351,4 +459,12 @@
 
         RTPOINT Pos = {0};
+        const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor);
+        uint32_t fbPitch = (pCompRect->xRight - pCompRect->xLeft) * 4;
+        uint32_t fbHeight = pCompRect->yBottom - pCompRect->yTop;
+
+        uint32_t dstPitch = static_cast<uint32_t>(strX * fbPitch);
+        uint32_t dstHeight = static_cast<uint32_t>(strY * fbHeight);
+
+        bool fStretch = fbPitch != dstPitch || fbHeight != dstHeight;
 
         for (uint32_t i = 0; i < cRects; ++i)
@@ -363,5 +479,8 @@
                     continue;
 
-                crFbBltImg(hFb->pvVram, CrVrScrCompositorRectGet(&hFb->Compositor), false, &Intersection, pPoint, pImg);
+                if (!fStretch)
+                    crFbBltImg(hFb->pvVram, pCompRect, false, &Intersection, &SrcPoint, pImg);
+                else
+                    crFbBltImgStretched(hFb->pvVram, pCompRect, false, &Intersection, &SrcPoint, strX, strY, pImg);
             }
         }
@@ -373,8 +492,66 @@
         CrTdBltLeave(pEnteredTex);
 
+    if (pEnteredBlitter)
+        CrBltLeave(pEnteredBlitter);
+
     VBoxVrListClear(&List);
 
     return rc;
 }
+
+static int crFbBltGetContentsStretchCPU(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 crFbBltGetContentsStretchCPU(hFb, pSrcRect, cRects, pRects, pImg);
+}
+
 
 int CrFbResize(CR_FRAMEBUFFER *pFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM)
@@ -454,33 +631,4 @@
 }
 
-typedef union CR_FBENTRY_FLAGS
-{
-    struct {
-        uint32_t fCreateNotified : 1;
-        uint32_t fInList         : 1;
-        uint32_t Reserved        : 30;
-    };
-    uint32_t Value;
-} CR_FBENTRY_FLAGS;
-
-typedef struct CR_FRAMEBUFFER_ENTRY
-{
-    VBOXVR_SCR_COMPOSITOR_ENTRY Entry;
-    RTLISTNODE Node;
-    uint32_t cRefs;
-    CR_FBENTRY_FLAGS Flags;
-    CRHTABLE HTable;
-} CR_FRAMEBUFFER_ENTRY;
-
-typedef struct CR_FBTEX
-{
-    CR_TEXDATA Tex;
-    CRTextureObj *pTobj;
-} CR_FBTEX;
-
-#define PCR_FBTEX_FROM_TEX(_pTex) ((CR_FBTEX*)((uint8_t*)(_pTex) - RT_OFFSETOF(CR_FBTEX, Tex)))
-#define PCR_FRAMEBUFFER_FROM_COMPOSITOR(_pCompositor) ((CR_FRAMEBUFFER*)((uint8_t*)(_pCompositor) - RT_OFFSETOF(CR_FRAMEBUFFER, Compositor)))
-#define PCR_FBENTRY_FROM_ENTRY(_pEntry) ((CR_FRAMEBUFFER_ENTRY*)((uint8_t*)(_pEntry) - RT_OFFSETOF(CR_FRAMEBUFFER_ENTRY, Entry)))
-
 #define CR_PMGR_MODE_WINDOW 0x1
 /* mutually exclusive with CR_PMGR_MODE_WINDOW */
@@ -661,5 +809,5 @@
         CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry);
         if (pTex)
-            CrTdBltDataDiscardNe(pTex);
+            CrTdBltDataInvalidateNe(pTex);
     }
 }
@@ -702,10 +850,14 @@
 
         CrHTableMoveTo(&pFbEntry->HTable, &pFbReplacingEntry->HTable);
+
+        CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry);
+        CR_TEXDATA *pReplacingTex = CrVrScrCompositorEntryTexGet(&pFbReplacingEntry->Entry);
+
+        CrTdBltStretchCacheMoveTo(pTex, pReplacingTex);
+
         if (pFb->pDisplay)
             pFb->pDisplay->EntryReplaced(pFb, pFbReplacingEntry, pFbEntry);
 
-        CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry);
-        if (pTex)
-            CrTdBltDataDiscardNe(pTex);
+        CrTdBltDataInvalidateNe(pTex);
 
         /* 2. mark the replaced entry is destroyed */
@@ -727,5 +879,5 @@
             CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry);
             if (pTex)
-                CrTdBltDataDiscardNe(pTex);
+                CrTdBltDataInvalidateNe(pTex);
         }
     }
@@ -791,5 +943,5 @@
         CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry);
         if (pTex)
-            CrTdBltDataDiscardNe(pTex);
+            CrTdBltDataInvalidateNe(pTex);
     }
 
@@ -931,5 +1083,5 @@
                 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry);
                 if (pTex)
-                    CrTdBltDataDiscardNe(pTex);
+                    CrTdBltDataInvalidateNe(pTex);
             }
         }
@@ -1005,5 +1157,5 @@
                 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry);
                 if (pTex)
-                    CrTdBltDataDiscardNe(pTex);
+                    CrTdBltDataInvalidateNe(pTex);
             }
         }
@@ -2791,28 +2943,16 @@
         CR_TEXDATA *pNewTex = CrVrScrCompositorEntryTexGet(pNewEntry);
 
-        rc = CrTdBltEnter(pReplacedTex);
+        CrTdBltDataInvalidateNe(pReplacedTex);
+
+        rc = CrTdBltEnter(pNewTex);
         if (RT_SUCCESS(rc))
         {
-            if (pNewTex != pReplacedTex)
-            {
-                CrTdBltDataDiscard(pReplacedTex);
-                rc = CrTdBltEnter(pNewTex);
-                if (RT_SUCCESS(rc))
-                {
-                    rc = vrdpFrame(hNewEntry);
-                    CrTdBltLeave(pNewTex);
-                }
-                else
-                    WARN(("CrTdBltEnter failed %d", rc));
-            }
-            else
-                rc = vrdpFrame(hNewEntry);
-
-            CrTdBltLeave(pReplacedTex);
+            rc = vrdpFrame(hNewEntry);
+            CrTdBltLeave(pNewTex);
         }
         else
             WARN(("CrTdBltEnter failed %d", rc));
 
-    	return rc;
+        return rc;
     }
 
@@ -2849,4 +2989,8 @@
             return rc;
         }
+
+        const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry);
+        CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
+        CrTdBltDataInvalidateNe(pTex);
 
         return vrdpRegions(pFb, hEntry);
@@ -2990,5 +3134,5 @@
     	CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
     	const CR_BLITTER_IMG *pImg;
-        CrTdBltDataDiscard(pTex);
+    	CrTdBltDataInvalidateNe(pTex);
     	int rc = CrTdBltDataAcquire(pTex, GL_BGRA, !!(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS), &pImg);
     	if (!RT_SUCCESS(rc))
@@ -3187,4 +3331,31 @@
 }
 #endif
+
+class CrFbDisplayEntryDataMonitor : public CrFbDisplayBase
+{
+public:
+    virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry)
+    {
+        entryDataChanged(pFb, hReplacedEntry);
+        return VINF_SUCCESS;
+    }
+
+    virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+    {
+        entryDataChanged(pFb, hEntry);
+        return VINF_SUCCESS;
+    }
+
+    virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+    {
+        entryDataChanged(pFb, hEntry);
+        return VINF_SUCCESS;
+    }
+protected:
+    virtual void entryDataChanged(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+    {
+
+    }
+};
 
 int CrPMgrInit()
@@ -4250,5 +4421,9 @@
                 uint8_t *pu8Buf = g_pvVRamBase + offVRAM;
 
-                RTPOINT Pos = {pBlt->Pos.x, pBlt->Pos.y};
+                RTRECT Rect;
+                Rect.xLeft = pBlt->Pos.x;
+                Rect.yTop = pBlt->Pos.y;
+                Rect.xRight = Rect.xLeft + pScreen->u32Width;
+                Rect.yBottom = Rect.yTop + pScreen->u32Height;
                 CR_BLITTER_IMG Img;
                 Img.pvData = pu8Buf;
@@ -4259,5 +4434,5 @@
                 Img.bpp = pScreen->u16BitsPerPixel;
                 Img.pitch = pScreen->u32LineSize;
-                int rc = CrFbBltGetContents(hFb, &Pos, cRects, pRects, &Img);
+                int rc = CrFbBltGetContents(hFb, &Rect, cRects, pRects, &Img);
                 if (!RT_SUCCESS(rc))
                 {
Index: /trunk/src/VBox/Main/include/DisplayImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/DisplayImpl.h	(revision 50363)
+++ /trunk/src/VBox/Main/include/DisplayImpl.h	(revision 50364)
@@ -363,4 +363,8 @@
     static int  displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height);
 
+#ifdef VBOX_WITH_CROGL
+    static BOOL  displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pu8Data, uint32_t u32Width, uint32_t u32Height);
+#endif
+
 private:
     static void InvalidateAndUpdateEMT(Display *pDisplay, unsigned uId, bool fUpdateAll);
Index: /trunk/src/VBox/Main/src-client/DisplayImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 50363)
+++ /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 50364)
@@ -152,4 +152,5 @@
 #ifdef VBOX_WITH_CROGL
     RT_ZERO(mCrOglCallbacks);
+    RT_ZERO(mCrOglScreenshotData);
     mfCrOglVideoRecState = CRVREC_STATE_IDLE;
     mCrOglScreenshotData.u32Screen = CRSCREEN_ALL;
@@ -2415,4 +2416,52 @@
 }
 
+#ifdef VBOX_WITH_CROGL
+BOOL Display::displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pu8Data, uint32_t u32Width, uint32_t u32Height)
+{
+    BOOL is3denabled;
+    pDisplay->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
+    if (is3denabled && pDisplay->mCrOglCallbacks.pfnHasData())
+    {
+        VMMDev *pVMMDev = pDisplay->mParent->getVMMDev();
+        if (pVMMDev)
+        {
+            CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)RTMemAlloc(sizeof (*pScreenshot));
+            if (pScreenshot)
+            {
+                /* screen id or CRSCREEN_ALL to specify all enabled */
+                pScreenshot->u32Screen = aScreenId;
+                pScreenshot->u32Width = u32Width;
+                pScreenshot->u32Height = u32Height;
+                pScreenshot->u32Pitch = u32Width * 4;
+                pScreenshot->pvBuffer = pu8Data;
+                pScreenshot->pvContext = NULL;
+                pScreenshot->pfnScreenshotBegin = NULL;
+                pScreenshot->pfnScreenshotPerform = NULL;
+                pScreenshot->pfnScreenshotEnd = NULL;
+
+                VBOXHGCMSVCPARM parm;
+
+                parm.type = VBOX_HGCM_SVC_PARM_PTR;
+                parm.u.pointer.addr = pScreenshot;
+                parm.u.pointer.size = sizeof (*pScreenshot);
+
+                int rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_TAKE_SCREENSHOT, 1, &parm);
+
+                RTMemFree(pScreenshot);
+
+                if (RT_SUCCESS(rc))
+                    return TRUE;
+                else
+                {
+                    AssertMsgFailed(("failed to get screenshot data from crOgl %d\n", rc));
+                    /* fall back to the non-3d mechanism */
+                }
+            }
+        }
+    }
+    return FALSE;
+}
+#endif
+
 int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height)
 {
@@ -2510,4 +2559,9 @@
     uint32_t cy = 0;
     int vrc = VINF_SUCCESS;
+
+# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
+    if (Display::displayCheckTakeScreenshotCrOgl(pDisplay, aScreenId, (uint8_t*)address, width, height))
+        return VINF_SUCCESS;
+#endif
 
     int cRetries = 5;
