Index: trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPTypes.h
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPTypes.h	(revision 99862)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPTypes.h	(revision 99990)
@@ -226,7 +226,6 @@
             struct
             {
-                RTR0MEMOBJ      hMemObjGB;                  /* Guest backing pages for host segment 3. */
-                struct VMSVGAMOB *pMob;                     /* Mob for the pages. */
-            } gb;
+                struct VMSVGAMOB *pMob;                     /* Mob for the pages (including RTR0MEMOBJ). */
+            } gb; /** @todo remove the struct */
         };
     } dx;
Index: trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/Svga.cpp
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/Svga.cpp	(revision 99862)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/Svga.cpp	(revision 99990)
@@ -190,5 +190,5 @@
                                    STATUS_INSUFFICIENT_RESOURCES);
 
-        /* Command buffer completion callback to free the COT. */
+        /* Command buffer completion callback to free the OT. */
         struct VMSVGAOTFREE callbackData;
         callbackData.gbo = pOT->gbo;
@@ -231,8 +231,16 @@
         SvgaObjectTablesDestroy(pSvga);
 
-    /* Give the host some time to process them. */
-    LARGE_INTEGER Interval;
-    Interval.QuadPart = -(int64_t)100 /* ms */ * 10000;
-    KeDelayExecutionThread(KernelMode, FALSE, &Interval);
+    /* Wait for buffers to complete. Up to 5 seconds, arbitrary. */
+    int cIntervals = 0;
+    while (!SvgaCmdBufIsIdle(pSvga) && cIntervals++ < 50)
+    {
+        /* Give the host some time to process them. */
+        LARGE_INTEGER Interval;
+        Interval.QuadPart = -(int64_t)100 /* ms */ * 10000;
+        KeDelayExecutionThread(KernelMode, FALSE, &Interval);
+    }
+
+    if (pSvga->u32Caps & SVGA_CAP_COMMAND_BUFFERS)
+        SvgaCmdBufDestroy(pSvga);
 
     /* Disable IRQs. */
@@ -244,7 +252,4 @@
     /* Disable SVGA. */
     SVGARegWrite(pSvga, SVGA_REG_ENABLE, SVGA_REG_ENABLE_DISABLE);
-
-    if (pSvga->u32Caps & SVGA_CAP_COMMAND_BUFFERS)
-        SvgaCmdBufDestroy(pSvga);
 }
 
@@ -334,5 +339,19 @@
         }
 
+        /* Free the miniport mob at last. Can't use SvgaMobDestroy here because it tells the host to write a fence
+         * value to this mob. */
+        void *pvCmd = SvgaCmdBuf3dCmdReserve(pSvga, SVGA_3D_CMD_DESTROY_GB_MOB, sizeof(SVGA3dCmdDestroyGBMob), SVGA3D_INVALID_ID);
+        if (pvCmd)
+        {
+            SVGA3dCmdDestroyGBMob *pCmd = (SVGA3dCmdDestroyGBMob *)pvCmd;
+            pCmd->mobid = VMSVGAMOB_ID(pSvga->pMiniportMob);
+            SvgaCmdBufCommit(pSvga, sizeof(*pCmd));
+        }
+        else
+            AssertFailed();
+
         svgaHwStop(pSvga);
+
+        SvgaMobFree(pSvga, pSvga->pMiniportMob); /* After svgaHwStop because it waits for command buffer completion. */
 
         Status = pDxgkInterface->DxgkCbUnmapMemory(pDxgkInterface->DeviceHandle,
@@ -411,4 +430,42 @@
                     }
                 }
+
+                if (NT_SUCCESS(Status))
+                {
+                    uint32_t const cbMiniportMob = RT_ALIGN_32(sizeof(VMSVGAMINIPORTMOB), PAGE_SIZE);
+                    RTR0MEMOBJ hMemObjMiniportMob;
+                    int rc = RTR0MemObjAllocPageTag(&hMemObjMiniportMob, cbMiniportMob,
+                                                    false /* executable R0 mapping */, "VMSVGAMOB0");
+                    if (RT_SUCCESS(rc))
+                    {
+                        Status = SvgaMobCreate(pSvga, &pSvga->pMiniportMob, cbMiniportMob / PAGE_SIZE, 0);
+                        if (NT_SUCCESS(Status))
+                        {
+                            Status = SvgaMobSetMemObj(pSvga->pMiniportMob, hMemObjMiniportMob);
+                            if (NT_SUCCESS(Status))
+                            {
+                                void *pvCmd = SvgaCmdBuf3dCmdReserve(pSvga, SVGA_3D_CMD_DEFINE_GB_MOB64, sizeof(SVGA3dCmdDefineGBMob64), SVGA3D_INVALID_ID);
+                                if (pvCmd)
+                                {
+                                    SVGA3dCmdDefineGBMob64 *pCmd = (SVGA3dCmdDefineGBMob64 *)pvCmd;
+                                    pCmd->mobid       = VMSVGAMOB_ID(pSvga->pMiniportMob);
+                                    pCmd->ptDepth     = pSvga->pMiniportMob->gbo.enmMobFormat;
+                                    pCmd->base        = pSvga->pMiniportMob->gbo.base;
+                                    pCmd->sizeInBytes = pSvga->pMiniportMob->gbo.cbGbo;
+                                    SvgaCmdBufCommit(pSvga, sizeof(*pCmd));
+
+                                    pSvga->pMiniportMobData = (VMSVGAMINIPORTMOB volatile *)RTR0MemObjAddress(hMemObjMiniportMob);
+                                    memset((void *)pSvga->pMiniportMobData, 0, cbMiniportMob);
+                                    RTListInit(&pSvga->listMobDeferredDestruction);
+                                    //pSvga->u64MobFence = 0;
+                                }
+                                else
+                                    AssertFailedStmt(Status = STATUS_INSUFFICIENT_RESOURCES);
+                            }
+                        }
+                    }
+                    else
+                       AssertFailedStmt(Status = STATUS_INSUFFICIENT_RESOURCES);
+                }
             }
         }
@@ -420,8 +477,6 @@
     }
 
-    if (NT_SUCCESS(Status))
-    {
-        *ppSvga = pSvga;
-    }
+    /* Caller's 'cleanup on error' code needs this pointer */
+    *ppSvga = pSvga;
 
     return Status;
@@ -1819,4 +1874,5 @@
 } GAWDDMREGION;
 
+/** @todo Deferred destruction. */
 static void svgaFreeGBMobForGMR(VBOXWDDM_EXT_VMSVGA *pSvga, PVMSVGAMOB pMob)
 {
@@ -1845,5 +1901,5 @@
     if (NT_SUCCESS(Status))
     {
-        Status = SvgaGboFillPageTableForMemObj(&pRegion->pMob->gbo, pRegion->MemObj);
+        Status = SvgaMobSetMemObj(pRegion->pMob, pRegion->MemObj);
         Assert(NT_SUCCESS(Status));
         if (NT_SUCCESS(Status))
@@ -1884,9 +1940,13 @@
         pRegion->MapObjR3 = NIL_RTR0MEMOBJ;
     }
-    if (pRegion->MemObj != NIL_RTR0MEMOBJ)
-    {
-        int rc = RTR0MemObjFree(pRegion->MemObj, true /* fFreeMappings */);
-        AssertRC(rc);
-        pRegion->MemObj = NIL_RTR0MEMOBJ;
+    if (pRegion->pMob == NULL)
+    {
+        /* The memory will be deleted by SvgaMobFree. */
+        if (pRegion->MemObj != NIL_RTR0MEMOBJ)
+        {
+            int rc = RTR0MemObjFree(pRegion->MemObj, true /* fFreeMappings */);
+            AssertRC(rc);
+            pRegion->MemObj = NIL_RTR0MEMOBJ;
+        }
     }
 }
@@ -2359,4 +2419,11 @@
         SvgaGboFree(&pMob->gbo);
 
+        if (pMob->hMemObj != NIL_RTR0MEMOBJ)
+        {
+            int rc = RTR0MemObjFree(pMob->hMemObj, true);
+            AssertRC(rc);
+            pMob->hMemObj = NIL_RTR0MEMOBJ;
+        }
+
         NTSTATUS Status = SvgaMobIdFree(pSvga, VMSVGAMOB_ID(pMob));
         Assert(NT_SUCCESS(Status)); RT_NOREF(Status);
@@ -2394,18 +2461,11 @@
 }
 
-
-struct VMSVGACOTFREE
-{
-    PVMSVGAMOB pMob;
-    RTR0MEMOBJ hMemObj;
-};
-
-
-static DECLCALLBACK(void) svgaCOTMobFreeCb(VBOXWDDM_EXT_VMSVGA *pSvga, void *pvData, uint32_t cbData)
-{
-    AssertReturnVoid(cbData == sizeof(struct VMSVGACOTFREE));
-    struct VMSVGACOTFREE *p = (struct VMSVGACOTFREE *)pvData;
-    SvgaMobFree(pSvga, p->pMob);
-    RTR0MemObjFree(p->hMemObj, true);
+NTSTATUS SvgaMobSetMemObj(PVMSVGAMOB pMob,
+                          RTR0MEMOBJ hMemObj)
+{
+    NTSTATUS Status = SvgaGboFillPageTableForMemObj(&pMob->gbo, hMemObj);
+    if (NT_SUCCESS(Status))
+        pMob->hMemObj = hMemObj;
+    return Status;
 }
 
@@ -2462,5 +2522,5 @@
                      Status);
 
-    Status = SvgaGboFillPageTableForMemObj(&pMob->gbo, hMemObjCOT);
+    Status = SvgaMobSetMemObj(pMob, hMemObjCOT);
     AssertReturnStmt(NT_SUCCESS(Status),
                      SvgaMobFree(pSvga, pMob); RTR0MemObjFree(hMemObjCOT, true),
@@ -2516,23 +2576,14 @@
                                    STATUS_INSUFFICIENT_RESOURCES);
 
-        pvCmd = SvgaCmdBuf3dCmdReserve(pSvga, SVGA_3D_CMD_DESTROY_GB_MOB, sizeof(SVGA3dCmdDestroyGBMob), SVGA3D_INVALID_ID);
+        uint32_t cbCmdRequired = 0;
+        SvgaMobDestroy(pSvga, pCOT->pMob, NULL, 0, &cbCmdRequired);
+        pvCmd = SvgaCmdBufReserve(pSvga, cbCmdRequired, SVGA3D_INVALID_ID);
         if (pvCmd)
         {
-            SVGA3dCmdDestroyGBMob *pCmd = (SVGA3dCmdDestroyGBMob *)pvCmd;
-            pCmd->mobid = VMSVGAMOB_ID(pCOT->pMob);
-            SvgaCmdBufCommit(pSvga, sizeof(*pCmd));
-        }
-        else
-            AssertFailedReturnStmt(SvgaMobFree(pSvga, pMob); RTR0MemObjFree(hMemObjCOT, true),
-                                   STATUS_INSUFFICIENT_RESOURCES);
-
-        /* Command buffer completion callback to free the COT. */
-        struct VMSVGACOTFREE callbackData;
-        callbackData.pMob = pCOT->pMob;
-        callbackData.hMemObj = pCOT->hMemObj;
-        SvgaCmdBufSetCompletionCallback(pSvga, svgaCOTMobFreeCb, &callbackData, sizeof(callbackData));
+            SvgaMobDestroy(pSvga, pCOT->pMob, pvCmd, cbCmdRequired, &cbCmdRequired);
+            SvgaCmdBufCommit(pSvga, cbCmdRequired);
+        }
 
         pCOT->pMob = NULL;
-        pCOT->hMemObj = NIL_RTR0MEMOBJ;
     }
 
@@ -2540,7 +2591,76 @@
 
     pCOT->pMob = pMob;
-    pCOT->hMemObj = hMemObjCOT;
     pCOT->cEntries = cbCOT / s_acbEntry[enmType];
 
     return STATUS_SUCCESS;
 }
+
+
+
+/*
+ * Place mob destruction commands into the buffer and add the mob to the deferred destruction list.
+ *
+ * Makes sure that the MOB, in particular the mobid, is deallocated by the guest after the MOB deletion
+ * has been completed by the host.
+ *
+ * SVGA_3D_CMD_DESTROY_GB_MOB can be submitted to the host either in the miniport command buffer
+ * (VMSVGACBSTATE::pCBCurrent) or in a paging buffer due to DXGK_OPERATION_UNMAP_APERTURE_SEGMENT operation.
+ * These two ways are not synchronized. Therefore it is possible that the guest deletes a mob for an aperture segment
+ * in a paging buffer then allocates the same mobid and sends SVGA_3D_CMD_DEFINE_GB_MOB64 to the host for a COTable
+ * before the paging buffer is sent to the host.
+ *
+ * The driver uses SVGA_3D_CMD_DX_MOB_FENCE_64 command to notify the driver that the host had deleted a mob
+ * and frees deleted mobs in the DPC routine
+ */
+NTSTATUS SvgaMobDestroy(VBOXWDDM_EXT_VMSVGA *pSvga,
+                        PVMSVGAMOB pMob,
+                        void *pvCmd,
+                        uint32_t cbReserved,
+                        uint32_t *pcbCmd)
+{
+    uint32_t cbRequired = sizeof(SVGA3dCmdHeader) + sizeof(SVGA3dCmdDestroyGBMob)
+                        + sizeof(SVGA3dCmdHeader) + sizeof(SVGA3dCmdDXMobFence64);
+
+    *pcbCmd = cbRequired;
+    if (cbReserved < cbRequired)
+        return STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
+
+    uint8_t *pu8Cmd = (uint8_t *)pvCmd;
+    SVGA3dCmdHeader *pHdr;
+
+    pHdr = (SVGA3dCmdHeader *)pu8Cmd;
+    pHdr->id   = SVGA_3D_CMD_DESTROY_GB_MOB;
+    pHdr->size = sizeof(SVGA3dCmdDestroyGBMob);
+    pu8Cmd += sizeof(*pHdr);
+
+    {
+    SVGA3dCmdDestroyGBMob *pCmd = (SVGA3dCmdDestroyGBMob *)pu8Cmd;
+    pCmd->mobid = VMSVGAMOB_ID(pMob);
+    pu8Cmd += sizeof(*pCmd);
+    }
+
+    pMob->u64MobFence = ASMAtomicIncU64(&pSvga->u64MobFence);
+
+    pHdr = (SVGA3dCmdHeader *)pu8Cmd;
+    pHdr->id   = SVGA_3D_CMD_DX_MOB_FENCE_64;
+    pHdr->size = sizeof(SVGA3dCmdDXMobFence64);
+    pu8Cmd += sizeof(*pHdr);
+
+    {
+    SVGA3dCmdDXMobFence64 *pCmd = (SVGA3dCmdDXMobFence64 *)pu8Cmd;
+    pCmd->value = pMob->u64MobFence;
+    pCmd->mobId = VMSVGAMOB_ID(pSvga->pMiniportMob);
+    pCmd->mobOffset = RT_OFFSETOF(VMSVGAMINIPORTMOB, u64MobFence);
+    pu8Cmd += sizeof(*pCmd);
+    }
+
+    /* Add the mob to the deferred destruction queue. */
+    KIRQL OldIrql;
+    SvgaHostObjectsLock(pSvga, &OldIrql);
+    RTListAppend(&pSvga->listMobDeferredDestruction, &pMob->node);
+    SvgaHostObjectsUnlock(pSvga, OldIrql);
+
+    Assert((uintptr_t)pu8Cmd - (uintptr_t)pvCmd == cbRequired);
+
+    return STATUS_SUCCESS;
+}
Index: trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/Svga.h
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/Svga.h	(revision 99862)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/Svga.h	(revision 99990)
@@ -179,4 +179,7 @@
     HANDLE                      hAllocation;                /* Allocation which is bound to the mob. */
     VMSVGAGBO                   gbo;                        /* Gbo for this mob. */
+    RTR0MEMOBJ                  hMemObj;                    /* The guest memory if allocated by miniport. */
+    uint32_t                    u64MobFence;                /* Free by the guest when the host reports this fence value. */
+    RTLISTNODE                  node;                       /* VBOXWDDM_EXT_VMSVGA::listMobDeferredDestruction */
 } VMSVGAMOB, *PVMSVGAMOB;
 
@@ -257,4 +260,10 @@
     VMSVGAOT aOT[SVGA_OTABLE_DX_MAX];
 
+    PVMSVGAMOB pMiniportMob; /* Used by miniport to communicate with the device. */
+    struct VMSVGAMINIPORTMOB volatile *pMiniportMobData; /* Pointer to the miniport mob content. */
+
+    uint64_t volatile u64MobFence;
+    RTLISTANCHOR listMobDeferredDestruction; /* Mob to be deleted after. */
+
     /** Bitmap of used GMR ids. Bit 0 - GMR id 0, etc. */
     uint32_t *pu32GMRBits; /* Number of GMRs is controlled by the host (u32GmrMaxIds), so allocate the bitmap. */
@@ -275,8 +284,12 @@
 typedef struct VBOXWDDM_EXT_VMSVGA *PVBOXWDDM_EXT_VMSVGA;
 
+typedef struct VMSVGAMINIPORTMOB
+{
+    uint64_t u64MobFence; /* Host writes SVGA3dCmdDXMobFence64::value here. */
+} VMSVGAMINIPORTMOB;
+
 typedef struct VMSVGACOT
 {
     PVMSVGAMOB              pMob;                       /* COTable mob. */
-    RTR0MEMOBJ              hMemObj;                    /* COTable pages. */
     uint32_t                cEntries;                   /* How many objects can be stored in the COTable. */
 } VMSVGACOT, *PVMSVGACOT;
@@ -629,4 +642,11 @@
                        uint32_t cMobPages,
                        HANDLE hAllocation);
+NTSTATUS SvgaMobSetMemObj(PVMSVGAMOB pMob,
+                          RTR0MEMOBJ hMemObj);
+NTSTATUS SvgaMobDestroy(VBOXWDDM_EXT_VMSVGA *pSvga,
+                        PVMSVGAMOB pMob,
+                        void *pvCmd,
+                        uint32_t cbReserved,
+                        uint32_t *pcbCmd);
 
 NTSTATUS SvgaCOTNotifyId(VBOXWDDM_EXT_VMSVGA *pSvga,
Index: trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/SvgaFifo.cpp
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/SvgaFifo.cpp	(revision 99862)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/SvgaFifo.cpp	(revision 99990)
@@ -873,4 +873,27 @@
 
 
+bool SvgaCmdBufIsIdle(PVBOXWDDM_EXT_VMSVGA pSvga)
+{
+    PVMSVGACBSTATE pCBState = pSvga->pCBState;
+
+    bool fIdle = true;
+
+    KIRQL OldIrql;
+    KeAcquireSpinLock(&pCBState->SpinLock, &OldIrql);
+    for (unsigned i = 0; i < RT_ELEMENTS(pCBState->aCBContexts); ++i)
+    {
+        PVMSVGACBCONTEXT pCBCtx = &pCBState->aCBContexts[i];
+        if (pCBCtx->cSubmitted > 0)
+        {
+            fIdle = false;
+            break;
+        }
+    }
+    KeReleaseSpinLock(&pCBState->SpinLock, OldIrql);
+
+    return fIdle;
+}
+
+
 void SvgaCmdBufSetCompletionCallback(PVBOXWDDM_EXT_VMSVGA pSvga, PFNCBCOMPLETION pfn, void const *pv, uint32_t cb)
 {
Index: trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/SvgaFifo.h
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/SvgaFifo.h	(revision 99862)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/SvgaFifo.h	(revision 99990)
@@ -52,4 +52,5 @@
 void  SvgaCmdBufProcess(PVBOXWDDM_EXT_VMSVGA pSvga);
 void SvgaCmdBufSetCompletionCallback(PVBOXWDDM_EXT_VMSVGA pSvga, PFNCBCOMPLETION pfn, void const *pv, uint32_t cb);
+bool SvgaCmdBufIsIdle(PVBOXWDDM_EXT_VMSVGA pSvga);
 
 NTSTATUS SvgaCmdBufAllocUMD(PVBOXWDDM_EXT_VMSVGA pSvga, PHYSICAL_ADDRESS DmaBufferPhysicalAddress,
Index: trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPDX.cpp
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPDX.cpp	(revision 99862)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPDX.cpp	(revision 99990)
@@ -101,24 +101,14 @@
     AssertReturnVoid(pAllocation->dx.SegmentId == 3 || pAllocation->dx.desc.fPrimary);
 
-    void *pvCmd = SvgaCmdBuf3dCmdReserve(pSvga, SVGA_3D_CMD_DESTROY_GB_MOB, sizeof(SVGA3dCmdDestroyGBMob), SVGA3D_INVALID_ID);
+    uint32_t cbRequired = 0;
+    SvgaMobDestroy(pSvga, pAllocation->dx.gb.pMob, NULL, 0, &cbRequired);
+    void *pvCmd = SvgaCmdBufReserve(pSvga, cbRequired, SVGA3D_INVALID_ID);
     if (pvCmd)
     {
-        SVGA3dCmdDestroyGBMob *pCmd = (SVGA3dCmdDestroyGBMob *)pvCmd;
-        pCmd->mobid = VMSVGAMOB_ID(pAllocation->dx.gb.pMob);
-        SvgaCmdBufCommit(pSvga, sizeof(SVGA3dCmdDestroyGBMob));
-    }
-
-    if (pAllocation->dx.gb.pMob)
-    {
-        SvgaMobFree(pSvga, pAllocation->dx.gb.pMob);
-        pAllocation->dx.gb.pMob = NULL;
-    }
-
-    if (pAllocation->dx.gb.hMemObjGB != NIL_RTR0MEMOBJ)
-    {
-        RTR0MemObjFree(pAllocation->dx.gb.hMemObjGB, true);
-        pAllocation->dx.gb.hMemObjGB = NIL_RTR0MEMOBJ;
-    }
-
+        SvgaMobDestroy(pSvga, pAllocation->dx.gb.pMob, pvCmd, cbRequired, &cbRequired);
+        SvgaCmdBufCommit(pSvga, cbRequired);
+    }
+
+    pAllocation->dx.gb.pMob = NULL;
     pAllocation->dx.mobid = SVGA3D_INVALID_ID;
 }
@@ -132,5 +122,6 @@
 
     /* Allocate guest backing pages. */
-    int rc = RTR0MemObjAllocPageTag(&pAllocation->dx.gb.hMemObjGB, cbGB, false /* executable R0 mapping */, "VMSVGAGB");
+    RTR0MEMOBJ hMemObjGB;
+    int rc = RTR0MemObjAllocPageTag(&hMemObjGB, cbGB, false /* executable R0 mapping */, "VMSVGAGB");
     AssertRCReturn(rc, STATUS_INSUFFICIENT_RESOURCES);
 
@@ -140,5 +131,5 @@
     if (NT_SUCCESS(Status))
     {
-        Status = SvgaGboFillPageTableForMemObj(&pAllocation->dx.gb.pMob->gbo, pAllocation->dx.gb.hMemObjGB);
+        Status = SvgaMobSetMemObj(pAllocation->dx.gb.pMob, hMemObjGB);
         Assert(NT_SUCCESS(Status));
         if (NT_SUCCESS(Status))
@@ -755,6 +746,6 @@
             if (pBuildPagingBuffer->Fill.Destination.SegmentId == 3 || pAllocation->dx.desc.fPrimary)
             {
-                AssertReturn(pAllocation->dx.gb.hMemObjGB != NIL_RTR0MEMOBJ, STATUS_INVALID_PARAMETER);
-                pvDst = RTR0MemObjAddress(pAllocation->dx.gb.hMemObjGB);
+                AssertReturn(pAllocation->dx.gb.pMob->hMemObj != NIL_RTR0MEMOBJ, STATUS_INVALID_PARAMETER);
+                pvDst = RTR0MemObjAddress(pAllocation->dx.gb.pMob->hMemObj);
             }
             else
@@ -948,14 +939,11 @@
     AssertReturn(pMob, STATUS_INVALID_PARAMETER);
 
-    uint32_t cbRequired = sizeof(SVGA3dCmdHeader) + sizeof(SVGA3dCmdDestroyGBMob);
+    uint32_t cbRequired = 0;
+    SvgaMobDestroy(pSvga, pMob, NULL, 0, &cbRequired);
     if (pAllocation->dx.desc.enmAllocationType == VBOXDXALLOCATIONTYPE_SURFACE)
-    {
         cbRequired += sizeof(SVGA3dCmdHeader) + sizeof(SVGA3dCmdBindGBSurface);
-    }
 
     if (pBuildPagingBuffer->DmaSize < cbRequired)
-    {
         return STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
-    }
 
     uint8_t *pu8Cmd = (uint8_t *)pBuildPagingBuffer->pDmaBuffer;
@@ -978,20 +966,14 @@
     }
 
-    pHdr = (SVGA3dCmdHeader *)pu8Cmd;
-    pHdr->id   = SVGA_3D_CMD_DESTROY_GB_MOB;
-    pHdr->size = sizeof(SVGA3dCmdDestroyGBMob);
-    pu8Cmd += sizeof(*pHdr);
-
-    {
-    SVGA3dCmdDestroyGBMob *pCmd = (SVGA3dCmdDestroyGBMob *)pu8Cmd;
-    pCmd->mobid = pAllocation->dx.mobid;
-    pu8Cmd += sizeof(*pCmd);
-    }
+    uint32_t cbCmd = 0;
+    NTSTATUS Status = SvgaMobDestroy(pSvga, pMob, pu8Cmd,
+                                     cbRequired - ((uintptr_t)pu8Cmd - (uintptr_t)pBuildPagingBuffer->pDmaBuffer),
+                                     &cbCmd);
+    AssertReturn(NT_SUCCESS(Status), Status);
+    pu8Cmd += cbCmd;
+
+    pAllocation->dx.mobid = SVGA3D_INVALID_ID;
 
     *pcbCommands = (uintptr_t)pu8Cmd - (uintptr_t)pBuildPagingBuffer->pDmaBuffer;
-
-    SvgaMobFree(pSvga, pMob);
-    pAllocation->dx.mobid = SVGA3D_INVALID_ID;
-
     return STATUS_SUCCESS;
 }
Index: trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPGaWddm.cpp
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPGaWddm.cpp	(revision 99862)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPGaWddm.cpp	(revision 99990)
@@ -249,20 +249,14 @@
                 }
 
-                pvCmd = SvgaCmdBuf3dCmdReserve(pSvga, SVGA_3D_CMD_DESTROY_GB_MOB, sizeof(SVGA3dCmdDestroyGBMob), SVGA3D_INVALID_ID);
+                uint32_t cbRequired = 0;
+                SvgaMobDestroy(pSvga, pCOT->pMob, NULL, 0, &cbRequired);
+                pvCmd = SvgaCmdBufReserve(pSvga, cbRequired, SVGA3D_INVALID_ID);
                 if (pvCmd)
                 {
-                    SVGA3dCmdDestroyGBMob *pCmd = (SVGA3dCmdDestroyGBMob *)pvCmd;
-                    pCmd->mobid = VMSVGAMOB_ID(pCOT->pMob);
-                    SvgaCmdBufCommit(pSvga, sizeof(*pCmd));
+                    SvgaMobDestroy(pSvga, pCOT->pMob, pvCmd, cbRequired, &cbRequired);
+                    SvgaCmdBufCommit(pSvga, cbRequired);
                 }
 
-                SvgaMobFree(pSvga, pCOT->pMob);
                 pCOT->pMob = NULL;
-            }
-
-            if (pCOT->hMemObj != NIL_RTR0MEMOBJ)
-            {
-                RTR0MemObjFree(pCOT->hMemObj, true);
-                pCOT->hMemObj = NIL_RTR0MEMOBJ;
             }
         }
@@ -391,4 +385,22 @@
      }
      else if (u32FenceA == u32FenceB)
+     {
+         /* FenceA is equal to FenceB. */
+         return 0;
+     }
+
+     /* FenceA is older than FenceB. */
+     return 1;
+}
+
+
+static int gaFenceCmp64(uint64_t u64FenceA, uint64_t u64FenceB)
+{
+     if (   u64FenceA < u64FenceB
+         || u64FenceA - u64FenceB > UINT64_MAX / 2)
+     {
+         return -1; /* FenceA is newer than FenceB. */
+     }
+     else if (u64FenceA == u64FenceB)
      {
          /* FenceA is equal to FenceB. */
@@ -1620,4 +1632,44 @@
     if (ASMAtomicCmpXchgBool(&pSvga->fCommandBufferIrq, false, true) && pSvga->pCBState)
         SvgaCmdBufProcess(pSvga);
+
+    /*
+     * Deferred MOB destruction.
+     */
+    if (pSvga->pMiniportMobData)
+    {
+        uint64_t const u64MobFence = pSvga->pMiniportMobData->u64MobFence;
+
+        /* Move mobs which were deleted by the host to the local list under the lock. */
+        RTLISTANCHOR listDestroyedMobs;
+        RTListInit(&listDestroyedMobs);
+
+        SvgaHostObjectsLock(pSvga, &OldIrql);
+
+        if (!RTListIsEmpty(&pSvga->listMobDeferredDestruction))
+        {
+            PVMSVGAMOB pIter, pNext;
+            RTListForEachSafe(&pSvga->listMobDeferredDestruction, pIter, pNext, VMSVGAMOB, node)
+            {
+                if (gaFenceCmp64(pIter->u64MobFence, u64MobFence) <= 0)
+                {
+                    RTListNodeRemove(&pIter->node);
+                    RTListAppend(&listDestroyedMobs, &pIter->node);
+                }
+            }
+        }
+
+        SvgaHostObjectsUnlock(pSvga, OldIrql);
+
+        if (!RTListIsEmpty(&listDestroyedMobs))
+        {
+            PVMSVGAMOB pIter, pNext;
+            RTListForEachSafe(&listDestroyedMobs, pIter, pNext, VMSVGAMOB, node)
+            {
+                /* Delete the data. SvgaMobFree deallocates pIter. */
+                RTListNodeRemove(&pIter->node);
+                SvgaMobFree(pSvga, pIter);
+            }
+        }
+    }
 }
 
