Index: trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp	(revision 50946)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp	(revision 50947)
@@ -771,41 +771,57 @@
 }
 
-typedef struct VBOXCMDVBVA_NOTIFYCOMPLETED_CB
+typedef struct VBOXCMDVBVA_NOTIFYPREEMPT_CB
 {
     PVBOXMP_DEVEXT pDevExt;
     VBOXCMDVBVA *pVbva;
-    volatile UINT *pu32FenceId;
-    DXGK_INTERRUPT_TYPE enmComplType;
-} VBOXCMDVBVA_NOTIFYCOMPLETED_CB, *PVBOXCMDVBVA_NOTIFYCOMPLETED_CB;
-
-static BOOLEAN vboxCmdVbvaDdiNotifyCompleteCb(PVOID pvContext)
-{
-    PVBOXCMDVBVA_NOTIFYCOMPLETED_CB pData = (PVBOXCMDVBVA_NOTIFYCOMPLETED_CB)pvContext;
-    if (*pData->pu32FenceId)
-    {
-        UINT u32FenceId = *pData->pu32FenceId;
-        *pData->pu32FenceId = 0;
-
-        vboxCmdVbvaDdiNotifyCompleteIrq(pData->pDevExt, pData->pVbva, u32FenceId, pData->enmComplType);
-
-        pData->pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pData->pDevExt->u.primary.DxgkInterface.DeviceHandle);
-
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-static int vboxCmdVbvaDdiNotifyComplete(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, volatile UINT *pu32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
-{
-    VBOXCMDVBVA_NOTIFYCOMPLETED_CB Data;
+    int rc;
+    UINT u32SubmitFenceId;
+    UINT u32PreemptFenceId;
+} VBOXCMDVBVA_NOTIFYPREEMPT_CB;
+
+static BOOLEAN vboxCmdVbvaDdiNotifyPreemptCb(PVOID pvContext)
+{
+    VBOXCMDVBVA_NOTIFYPREEMPT_CB* pData = (VBOXCMDVBVA_NOTIFYPREEMPT_CB*)pvContext;
+    PVBOXMP_DEVEXT pDevExt = pData->pDevExt;
+    VBOXCMDVBVA *pVbva = pData->pVbva;
+    if (!pData->u32SubmitFenceId || pVbva->u32FenceCompleted == pData->u32SubmitFenceId)
+    {
+        vboxCmdVbvaDdiNotifyCompleteIrq(pDevExt, pVbva, pData->u32PreemptFenceId, DXGK_INTERRUPT_DMA_PREEMPTED);
+
+        pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
+    }
+    else
+    {
+        Assert(pVbva->u32FenceCompleted < pData->u32SubmitFenceId);
+        Assert(pVbva->cPreempt <= VBOXCMDVBVA_PREEMPT_EL_SIZE);
+        if (pVbva->cPreempt == VBOXCMDVBVA_PREEMPT_EL_SIZE)
+        {
+            WARN(("no more free elements in preempt map"));
+            pData->rc = VERR_BUFFER_OVERFLOW;
+            return FALSE;
+        }
+        uint32_t iNewEl = (pVbva->iCurPreempt + pVbva->cPreempt) % VBOXCMDVBVA_PREEMPT_EL_SIZE;
+        Assert(iNewEl < VBOXCMDVBVA_PREEMPT_EL_SIZE);
+        pVbva->aPreempt[iNewEl].u32SubmitFence = pData->u32SubmitFenceId;
+        pVbva->aPreempt[iNewEl].u32PreemptFence = pData->u32PreemptFenceId;
+        ++pVbva->cPreempt;
+    }
+
+    pData->rc = VINF_SUCCESS;
+    return TRUE;
+}
+
+static int vboxCmdVbvaDdiNotifyPreempt(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, UINT u32SubmitFenceId, UINT u32PreemptFenceId)
+{
+    VBOXCMDVBVA_NOTIFYPREEMPT_CB Data;
     Data.pDevExt = pDevExt;
     Data.pVbva = pVbva;
-    Data.pu32FenceId = pu32FenceId;
-    Data.enmComplType = enmComplType;
+    Data.rc = VERR_INTERNAL_ERROR;
+    Data.u32SubmitFenceId = u32SubmitFenceId;
+    Data.u32PreemptFenceId = u32PreemptFenceId;
     BOOLEAN bDummy;
     NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
             pDevExt->u.primary.DxgkInterface.DeviceHandle,
-            vboxCmdVbvaDdiNotifyCompleteCb,
+            vboxCmdVbvaDdiNotifyPreemptCb,
             &Data,
             0, /* IN ULONG MessageNumber */
@@ -816,5 +832,12 @@
         return VERR_GENERAL_FAILURE;
     }
-    return Status;
+
+    if (!RT_SUCCESS(Data.rc))
+    {
+        WARN(("vboxCmdVbvaDdiNotifyPreemptCb failed rc %d", Data.rc));
+        return Data.rc;
+    }
+
+    return VINF_SUCCESS;
 }
 
@@ -1004,6 +1027,7 @@
     bool fProcessed;
     uint8_t* pu8Cmd;
-    bool fFenceFound = false;
-
+    uint32_t u32SubmitFence = 0;
+
+    /* we can do it right here */
     while ((pu8Cmd = (uint8_t*)VBoxVBVAExBIterNext(&Iter, &cbBuffer, &fProcessed)) != NULL)
     {
@@ -1013,22 +1037,15 @@
         VBOXCMDVBVA_HDR *pCmd = (VBOXCMDVBVA_HDR*)pu8Cmd;
 
-        if (pCmd->u32FenceID != u32FenceID)
+        if (ASMAtomicCmpXchgU8(&pCmd->u8State, VBOXCMDVBVA_STATE_CANCELLED, VBOXCMDVBVA_STATE_SUBMITTED)
+                || pCmd->u8State == VBOXCMDVBVA_STATE_CANCELLED)
             continue;
 
-        fFenceFound = true;
-
-        if (!ASMAtomicCmpXchgU8(&pCmd->u8State, VBOXCMDVBVA_STATE_CANCELLED, VBOXCMDVBVA_STATE_SUBMITTED))
-        {
-            Assert(pCmd->u8State == VBOXCMDVBVA_STATE_IN_PROGRESS);
-            break;
-        }
-
-        /* we have canceled the command successfully */
-        vboxCmdVbvaDdiNotifyComplete(pDevExt, pVbva, &pCmd->u32FenceID, DXGK_INTERRUPT_DMA_PREEMPTED);
-        return true;
-    }
-
-    if (!fFenceFound)
-        vboxCmdVbvaDdiNotifyComplete(pDevExt, pVbva, &u32FenceID, DXGK_INTERRUPT_DMA_PREEMPTED);
+        Assert(pCmd->u8State == VBOXCMDVBVA_STATE_IN_PROGRESS);
+
+        u32SubmitFence = ASMAtomicUoReadU32(&pCmd->u32FenceID);
+        break;
+    }
+
+    vboxCmdVbvaDdiNotifyPreempt(pDevExt, pVbva, u32SubmitFence, u32FenceID);
 
     return false;
@@ -1061,27 +1078,38 @@
         Assert(u32FenceID);
         VBoxVBVAExCBufferCompleted(&pVbva->Vbva);
-        DXGK_INTERRUPT_TYPE enmDdiNotify;
 
         if (u8State == VBOXCMDVBVA_STATE_IN_PROGRESS)
         {
-            if (u32FenceID)
+            Assert(u32FenceID);
+            if (!u32FenceID)
+                continue;
+
+#ifdef DEBUG_misha
+            Assert(u32FenceID == pVbva->u32FenceCompleted + 1);
+#endif
+            pVbva->u32FenceCompleted = u32FenceID;
+        }
+        else
+        {
+            Assert(u8State == VBOXCMDVBVA_STATE_CANCELLED);
+            continue;
+        }
+
+        Assert(u32FenceID);
+        vboxCmdVbvaDdiNotifyCompleteIrq(pDevExt, pVbva, u32FenceID, DXGK_INTERRUPT_DMA_COMPLETED);
+
+        if (pVbva->cPreempt && pVbva->aPreempt[pVbva->iCurPreempt].u32SubmitFence == u32FenceID)
+        {
+            Assert(pVbva->aPreempt[pVbva->iCurPreempt].u32PreemptFence);
+            vboxCmdVbvaDdiNotifyCompleteIrq(pDevExt, pVbva, pVbva->aPreempt[pVbva->iCurPreempt].u32PreemptFence, DXGK_INTERRUPT_DMA_PREEMPTED);
+            --pVbva->cPreempt;
+            if (!pVbva->cPreempt)
+                pVbva->iCurPreempt = 0;
+            else
             {
-#ifdef DEBUG_misha
-                Assert(u32FenceID == pVbva->u32FenceCompleted + 1);
-#endif
-                pVbva->u32FenceCompleted = u32FenceID;
+                ++pVbva->iCurPreempt;
+                pVbva->iCurPreempt %= VBOXCMDVBVA_PREEMPT_EL_SIZE;
             }
-            enmDdiNotify = DXGK_INTERRUPT_DMA_COMPLETED;
-        }
-        else
-        {
-            Assert(u8State == VBOXCMDVBVA_STATE_CANCELLED);
-            enmDdiNotify = DXGK_INTERRUPT_DMA_PREEMPTED;
-            /* to prevent concurrent notifications from DdiPreemptCommand */
-            pCmd->u32FenceID = 0;
-        }
-
-        if (u32FenceID)
-            vboxCmdVbvaDdiNotifyCompleteIrq(pDevExt, pVbva, u32FenceID, enmDdiNotify);
+        }
 
         fHasCommandsCompletedPreempted = true;
Index: trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h	(revision 50946)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h	(revision 50947)
@@ -116,4 +116,12 @@
 #define VBOXCMDVBVA_BUFFERSIZE(_cbCmdApprox) (RT_OFFSETOF(VBVABUFFER, au8Data) + ((RT_SIZEOFMEMB(VBVABUFFER, aRecords)/RT_SIZEOFMEMB(VBVABUFFER, aRecords[0])) * (_cbCmdApprox)))
 
+typedef struct VBOXCMDVBVA_PREEMPT_EL
+{
+    uint32_t u32SubmitFence;
+    uint32_t u32PreemptFence;
+} VBOXCMDVBVA_PREEMPT_EL;
+
+#define VBOXCMDVBVA_PREEMPT_EL_SIZE 16
+
 typedef struct VBOXCMDVBVA
 {
@@ -127,4 +135,8 @@
     /* node ordinal */
     uint32_t idNode;
+
+    uint32_t cPreempt;
+    uint32_t iCurPreempt;
+    VBOXCMDVBVA_PREEMPT_EL aPreempt[VBOXCMDVBVA_PREEMPT_EL_SIZE];
 } VBOXCMDVBVA;
 
