Index: /trunk/src/VBox/Frontends/VBoxSDL/Framebuffer.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxSDL/Framebuffer.cpp	(revision 51626)
+++ /trunk/src/VBox/Frontends/VBoxSDL/Framebuffer.cpp	(revision 51627)
@@ -419,4 +419,13 @@
 }
 
+STDMETHODIMP VBoxSDLFB::NotifyUpdateImage(ULONG aX,
+                                          ULONG aY,
+                                          ULONG aWidth,
+                                          ULONG aHeight,
+                                          ComSafeArrayIn(BYTE, aImage))
+{
+    return E_NOTIMPL;
+}
+
 extern ComPtr<IDisplay> gpDisplay;
 
Index: /trunk/src/VBox/Frontends/VBoxSDL/Framebuffer.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxSDL/Framebuffer.h	(revision 51626)
+++ /trunk/src/VBox/Frontends/VBoxSDL/Framebuffer.h	(revision 51627)
@@ -82,4 +82,5 @@
 
     STDMETHOD(NotifyUpdate)(ULONG x, ULONG y, ULONG w, ULONG h);
+    STDMETHOD(NotifyUpdateImage)(ULONG x, ULONG y, ULONG w, ULONG h, ComSafeArrayIn(BYTE, aImage));
     STDMETHOD(NotifyChange)(ULONG aScreenId,
                             ULONG aXOrigin,
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp	(revision 51626)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp	(revision 51627)
@@ -263,4 +263,13 @@
 }
 
+STDMETHODIMP UIFrameBuffer::NotifyUpdateImage(ULONG aX,
+                                              ULONG aY,
+                                              ULONG aWidth,
+                                              ULONG aHeight,
+                                              ComSafeArrayIn(BYTE, aImage))
+{
+    return E_NOTIMPL;
+}
+
 STDMETHODIMP UIFrameBuffer::VideoModeSupported(ULONG uWidth, ULONG uHeight, ULONG uBPP, BOOL *pfSupported)
 {
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.h	(revision 51626)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.h	(revision 51627)
@@ -127,4 +127,5 @@
       * @note         Calls to this and #setMarkAsUnused method are synchronized (from GUI side). */
     STDMETHOD(NotifyUpdate)(ULONG uX, ULONG uY, ULONG uWidth, ULONG uHeight);
+    STDMETHOD(NotifyUpdateImage)(ULONG x, ULONG y, ULONG w, ULONG h, ComSafeArrayIn(BYTE, aImage));
 
     /** EMT callback: Returns whether the frame-buffer implementation is willing to support a given video-mode.
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 51626)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 51627)
@@ -15234,4 +15234,24 @@
   </enum>
 
+  <enum
+    name="FramebufferUpdateMode"
+    uuid="1268d8ab-dd2f-443c-bc56-d93d3ced5cde"
+    >
+    <desc>
+      How a framebuffer is notified about screen updates.
+    </desc>
+
+    <const name="NotifyUpdate"       value="0">
+      <desc>
+        IFramebuffer::NotifyUpdate is called.
+      </desc>
+    </const>
+    <const name="NotifyUpdateImage"  value="1">
+      <desc>
+        IFramebuffer::NotifyUpdateImage is called.
+      </desc>
+    </const>
+  </enum>
+
   <interface
     name="IDisplaySourceBitmap" extends="$unknown" wsmap="suppress"
@@ -15253,5 +15273,5 @@
   <interface
     name="IFramebuffer" extends="$unknown"
-    uuid="929e4228-f7cf-436d-99a0-dcf6596473b2"
+    uuid="c42d2714-6263-473f-a6c4-3d3b38983e74"
     wsmap="managed"
     >
@@ -15334,4 +15354,19 @@
       <param name="width" type="unsigned long" dir="in"/>
       <param name="height" type="unsigned long" dir="in"/>
+    </method>
+
+    <method name="notifyUpdateImage">
+      <desc>
+        Informs about an update and provides 32bpp bitmap.
+      </desc>
+      <param name="x" type="unsigned long" dir="in"/>
+      <param name="y" type="unsigned long" dir="in"/>
+      <param name="width" type="unsigned long" dir="in"/>
+      <param name="height" type="unsigned long" dir="in"/>
+      <param name="image" type="octet" dir="in" safearray="yes">
+        <desc>
+          Array with 32BPP image data.
+        </desc>
+      </param>
     </method>
 
@@ -15517,5 +15552,5 @@
   <interface
     name="IDisplay" extends="$unknown"
-    uuid="efd0567f-8697-4b4c-965a-7f3672d1909e"
+    uuid="0d85a960-bfa7-4f26-9637-fdd521b7f3c1"
     wsmap="managed"
     >
@@ -15851,4 +15886,10 @@
       <param name="screenId" type="unsigned long" dir="in"/>
       <param name="displaySourceBitmap" type="IDisplaySourceBitmap" dir="out"/>
+    </method>
+
+    <method name="setFramebufferUpdateMode">
+      <desc>Select how the framebuffer is informed about screen updates.</desc>
+      <param name="screenId" type="unsigned long" dir="in"/>
+      <param name="framebufferUpdateMode" type="FramebufferUpdateMode" dir="in"/>
     </method>
 
Index: /trunk/src/VBox/Main/include/DisplayImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/DisplayImpl.h	(revision 51626)
+++ /trunk/src/VBox/Main/include/DisplayImpl.h	(revision 51627)
@@ -46,4 +46,13 @@
     ComPtr<IDisplaySourceBitmap> pSourceBitmap;
     bool fDisabled;
+
+    FramebufferUpdateMode_T enmFramebufferUpdateMode;
+
+    struct
+    {
+        ComPtr<IDisplaySourceBitmap> pSourceBitmap;
+        uint8_t *pu8Address;
+        uint32_t cbLine;
+    } updateImage;
 
     LONG xOrigin;
@@ -204,11 +213,10 @@
     STDMETHOD(QuerySourceBitmap)(ULONG aScreenId,
                                  IDisplaySourceBitmap **aDisplaySourceBitmap);
+    STDMETHOD(SetFramebufferUpdateMode)(ULONG aScreenId,
+                                        FramebufferUpdateMode_T aFramebufferUpdateMode);
 
     static const PDMDRVREG  DrvReg;
 
 private:
-
-    HRESULT querySourceBitmap(ULONG aScreenId,
-                              IDisplaySourceBitmap **ppDisplaySourceBitmap);
 
 #ifdef VBOX_WITH_CRHGSMI
Index: /trunk/src/VBox/Main/src-client/DisplayImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 51626)
+++ /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 51627)
@@ -600,4 +600,9 @@
         maFramebuffers[ul].fDisabled = ul > 0;
 
+        maFramebuffers[ul].enmFramebufferUpdateMode = FramebufferUpdateMode_NotifyUpdate;
+
+        maFramebuffers[ul].updateImage.pu8Address = NULL;
+        maFramebuffers[ul].updateImage.cbLine = 0;
+
         maFramebuffers[ul].xOrigin = 0;
         maFramebuffers[ul].yOrigin = 0;
@@ -660,4 +665,7 @@
     {
         maFramebuffers[uScreenId].pSourceBitmap.setNull();
+        maFramebuffers[uScreenId].updateImage.pSourceBitmap.setNull();
+        maFramebuffers[uScreenId].updateImage.pu8Address = NULL;
+        maFramebuffers[uScreenId].updateImage.cbLine = 0;
         maFramebuffers[uScreenId].pFramebuffer.setNull();
     }
@@ -896,4 +904,6 @@
         return VINF_SUCCESS;
     }
+
+    SetFramebufferUpdateMode(uScreenId, FramebufferUpdateMode_NotifyUpdate);
 
     if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
@@ -1124,5 +1134,37 @@
     {
         if (w != 0 && h != 0)
-            pFramebuffer->NotifyUpdate(x, y, w, h);
+        {
+            if (RT_LIKELY(maFramebuffers[uScreenId].enmFramebufferUpdateMode == FramebufferUpdateMode_NotifyUpdate))
+            {
+                pFramebuffer->NotifyUpdate(x, y, w, h);
+            }
+            else if (maFramebuffers[uScreenId].enmFramebufferUpdateMode == FramebufferUpdateMode_NotifyUpdateImage)
+            {
+                AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+                DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
+
+                if (!pFBInfo->updateImage.pSourceBitmap.isNull())
+                {
+                    Assert(pFBInfo->updateImage.pu8Address);
+
+                    size_t cbData = w * h * 4;
+                    com::SafeArray<BYTE> image(cbData);
+
+                    uint8_t *pu8Dst = image.raw();
+                    const uint8_t *pu8Src = pFBInfo->updateImage.pu8Address + pFBInfo->updateImage.cbLine * y + x * 4;
+
+                    int i;
+                    for (i = y; i < y + h; ++i)
+                    {
+                        memcpy(pu8Dst, pu8Src, w * 4);
+                        pu8Dst += w * 4;
+                        pu8Src += pFBInfo->updateImage.cbLine;
+                    }
+
+                    pFramebuffer->NotifyUpdateImage(x, y, w, h, ComSafeArrayAsInParam(image));
+                }
+            }
+        }
     }
 
@@ -3383,4 +3425,7 @@
         return ptrVM.rc();
 
+    bool fSetRenderVRAM = false;
+    bool fInvalidate = false;
+
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
@@ -3389,25 +3434,11 @@
                         aScreenId, mcMonitors);
 
-    HRESULT hr = querySourceBitmap(aScreenId, aDisplaySourceBitmap);
-
-    alock.release();
-
-    LogRelFlowFunc(("%Rhrc\n", hr));
-    return hr;
-}
-
-// private methods
-/////////////////////////////////////////////////////////////////////////////
-
-HRESULT Display::querySourceBitmap(ULONG aScreenId,
-                                   IDisplaySourceBitmap **ppDisplaySourceBitmap)
-{
+    if (!mfSourceBitmapEnabled)
+    {
+        *aDisplaySourceBitmap = NULL;
+        return E_FAIL;
+    }
+
     HRESULT hr = S_OK;
-
-    if (!mfSourceBitmapEnabled)
-    {
-        *ppDisplaySourceBitmap = NULL;
-        return E_FAIL;
-    }
 
     DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
@@ -3424,8 +3455,5 @@
         if (SUCCEEDED(hr))
         {
-            pFBInfo->pSourceBitmap = obj;
-
-            /* Whether VRAM must be copied to the internal buffer. */
-            pFBInfo->fDefaultFormat = !obj->usesVRAM();
+            bool fDefaultFormat = !obj->usesVRAM();
 
             if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
@@ -3452,18 +3480,12 @@
                 mpDrv->IConnector.cy         = ulHeight;
 
-                if (pFBInfo->fDefaultFormat)
-                    mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, true);
+                fSetRenderVRAM = fDefaultFormat;
             }
 
-            if (pFBInfo->fDefaultFormat)
-            {
-                /* @todo make sure that the bitmap contains the latest image? */
-                Console::SafeVMPtrQuiet ptrVM(mParent);
-                if (ptrVM.isOk())
-                {
-//                    VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::InvalidateAndUpdateEMT,
-//                                     3, this, aScreenId, false);
-                }
-            }
+            /* Make sure that the bitmap contains the latest image. */
+            fInvalidate = fDefaultFormat;
+
+            pFBInfo->pSourceBitmap = obj;
+            pFBInfo->fDefaultFormat = fDefaultFormat;
         }
     }
@@ -3472,9 +3494,89 @@
     {
         pFBInfo->pSourceBitmap->AddRef();
-        *ppDisplaySourceBitmap = pFBInfo->pSourceBitmap;
-    }
-
+        *aDisplaySourceBitmap = pFBInfo->pSourceBitmap;
+    }
+
+    /* Leave the IDisplay lock because the VGA device must not be called under it. */
+    alock.release();
+
+    if (SUCCEEDED(hr))
+    {
+        if (fSetRenderVRAM)
+            mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, true);
+
+        if (fInvalidate)
+            VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::InvalidateAndUpdateEMT,
+                             3, this, aScreenId, false);
+    }
+
+    LogRelFlowFunc(("%Rhrc\n", hr));
     return hr;
 }
+
+STDMETHODIMP Display::SetFramebufferUpdateMode(ULONG aScreenId,
+                                               FramebufferUpdateMode_T aFramebufferUpdateMode)
+{
+    LogRelFlowFunc(("aScreenId %d, aFramebufferUpdateMode %d\n", aScreenId, aFramebufferUpdateMode));
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    HRESULT hr = S_OK;
+
+    /* Prepare without taking a lock. API has it's own locking. */
+    ComPtr<IDisplaySourceBitmap> pSourceBitmap;
+    if (aFramebufferUpdateMode == FramebufferUpdateMode_NotifyUpdateImage)
+    {
+        /* A source bitmap will be needed. */
+        hr = QuerySourceBitmap(aScreenId, pSourceBitmap.asOutParam());
+    }
+
+    if (FAILED(hr))
+        return hr;
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (aScreenId >= mcMonitors)
+        return setError(E_INVALIDARG, tr("SetFramebufferUpdateMode: Invalid screen %d (total %d)"),
+                        aScreenId, mcMonitors);
+
+    DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
+
+    /* Reset the update mode. */
+    pFBInfo->updateImage.pSourceBitmap.setNull();
+    pFBInfo->updateImage.pu8Address = NULL;
+    pFBInfo->updateImage.cbLine = 0;
+
+    if (aFramebufferUpdateMode == FramebufferUpdateMode_NotifyUpdateImage)
+    {
+        BYTE *pAddress = NULL;
+        ULONG ulWidth = 0;
+        ULONG ulHeight = 0;
+        ULONG ulBitsPerPixel = 0;
+        ULONG ulBytesPerLine = 0;
+        ULONG ulPixelFormat = 0;
+
+        hr = pSourceBitmap->QueryBitmapInfo(&pAddress,
+                                            &ulWidth,
+                                            &ulHeight,
+                                            &ulBitsPerPixel,
+                                            &ulBytesPerLine,
+                                            &ulPixelFormat);
+        if (SUCCEEDED(hr))
+        {
+            pFBInfo->updateImage.pSourceBitmap = pSourceBitmap;
+            pFBInfo->updateImage.pu8Address = pAddress;
+            pFBInfo->updateImage.cbLine = ulBytesPerLine;
+        }
+    }
+
+    pFBInfo->enmFramebufferUpdateMode = aFramebufferUpdateMode;
+
+    return S_OK;
+}
+
+
+// private methods
+/////////////////////////////////////////////////////////////////////////////
 
 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
