VirtualBox

Changeset 76884 in vbox for trunk/src/VBox/Additions


Ignore:
Timestamp:
Jan 18, 2019 10:45:23 AM (6 years ago)
Author:
vboxsync
Message:

WDDM: Gallium miniport driver: cleanup

Location:
trunk/src/VBox/Additions/WINNT/Graphics/Video/mp
Files:
1 added
2 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/Makefile.kmk

    r76553 r76884  
    180180        wddm/gallium/SvgaFifo.cpp \
    181181        wddm/gallium/SvgaHw.cpp \
     182        wddm/gallium/VBoxMPGaFence.cpp \
     183        wddm/gallium/VBoxMPGaUtils.cpp \
    182184        wddm/gallium/VBoxMPGaWddm.cpp
    183185 endif
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPGaFence.cpp

    r76845 r76884  
    1818#include "VBoxMPGaWddm.h"
    1919#include "../VBoxMPVidPn.h"
     20#include "VBoxMPGaExt.h"
    2021
    2122#include "Svga.h"
     
    2627#include <iprt/time.h>
    2728
    28 volatile uint32_t g_fu32GaLogControl =
    29 #ifdef DEBUG
    30     1 /* Enable LogRels */
    31 #else
    32     0 /* Disable LogRels, but they can be enabled if necessary. */
    33 #endif
    34 ;
    35 
    36 
    37 #define VBOXWDDM_GA_MAX_FENCE_OBJECTS 4096
    38 
    39 /* Gallium related device extension. */
    40 typedef struct VBOXWDDM_EXT_GA
    41 {
    42     union
    43     {
    44         /* Pointers to HW specific structs. */
    45         PVBOXWDDM_EXT_VMSVGA pSvga;
    46         void *pv;
    47     } hw;
    48 
    49     volatile uint32_t u32LastSubmittedFenceId; /* Updated in GaDxgkSubmitCommand. */
    50     volatile uint32_t u32LastCompletedFenceId; /* Updated in ISR. */
    51     volatile uint32_t u32PreemptionFenceId; /* Updated in GaDxgkDdiPreemptCommand. */
    52     volatile uint32_t u32LastCompletedSeqNo; /* Updated in DPC routine. */
    53 
    54     struct
    55     {
    56         /* Generation of SeqNo's. */
    57         volatile uint32_t u32SeqNoSource;
    58         /* Lock for accessing fence objects. Spin lock because it is used in DPC routine too. */
    59         KIRQL OldIrql;
    60         KSPIN_LOCK SpinLock;
    61         /* List of all fence objects. */
    62         RTLISTANCHOR list;
    63         /** Bitmap of used fence handles. Bit 0 - fence handle 0, etc. */
    64         uint32_t au32HandleBits[(VBOXWDDM_GA_MAX_FENCE_OBJECTS + 31) / 32];
    65     } fenceObjects;
    66 } VBOXWDDM_EXT_GA;
    67 
    68 /* Fence object (FO). */
    69 typedef struct GAFENCEOBJECT
    70 {
    71     volatile uint32_t cRefs;    /* By UM driver, by waiter, during submission. */
    72     uint32_t u32FenceHandle;    /* Unique identifier, used for communications with UM driver. */
    73     uint32_t u32FenceState;     /* GAFENCE_STATE_* */
    74     uint32_t fu32FenceFlags;    /* GAFENCE_F_* */
    75     uint32_t u32SubmissionFenceId; /* DXGK fence id. */
    76     uint32_t u32SeqNo;          /* Gallium Sequence Number, generated by the miniport. */
    77     PVBOXWDDM_DEVICE pDevice;   /* Device the fence is associated with. */
    78     KEVENT event;               /* Allows to wait for the fence completion. */
    79     RTLISTNODE node;            /* For the per adapter list of fence objects. */
    80     uint64_t u64SubmittedTS;    /* Nanoseconds timestamp when the corresponding buffer was submitted. */
    81 } GAFENCEOBJECT;
    82 
    83 #define GAFENCE_STATE_IDLE      0
    84 #define GAFENCE_STATE_SUBMITTED 1
    85 #define GAFENCE_STATE_SIGNALED  2
    86 
    87 #define GAFENCE_F_WAITED        0x1 /* KEVENT is initialized and there is(are) waiter(s). */
    88 
    89 
    90 /*
    91  * Helpers.
    92  */
    93 
    94 void *GaMemAlloc(uint32_t cbSize)
    95 {
    96     return ExAllocatePoolWithTag(NonPagedPool, cbSize, 'AGBV');
    97 }
    98 
    99 void *GaMemAllocZero(uint32_t cbSize)
    100 {
    101     void *pvMem = GaMemAlloc(cbSize);
    102     if (pvMem)
    103         memset(pvMem, 0, cbSize);
    104     return pvMem;
    105 }
    106 
    107 void GaMemFree(void *pvMem)
    108 {
    109     ExFreePool(pvMem);
    110 }
    111 
    112 NTSTATUS GaIdAlloc(uint32_t *pu32Bits,
    113                    uint32_t cbBits,
    114                    uint32_t u32Limit,
    115                    uint32_t *pu32Id)
    116 {
    117     /* Find the first zero bit. */
    118     const int32_t i32Id = ASMBitFirstClear(pu32Bits, cbBits * 8);
    119     if (0 <= i32Id && i32Id < (int32_t)u32Limit)
    120     {
    121         ASMBitSet(pu32Bits, i32Id);
    122         *pu32Id = (uint32_t)i32Id;
    123         return STATUS_SUCCESS;
    124     }
    125 
    126     return STATUS_INSUFFICIENT_RESOURCES;
    127 }
    128 
    129 NTSTATUS GaIdFree(uint32_t *pu32Bits,
    130                   uint32_t cbBits,
    131                   uint32_t u32Limit,
    132                   uint32_t u32Id)
    133 {
    134     AssertReturn(u32Limit <= cbBits * 8, STATUS_INVALID_PARAMETER);
    135     AssertReturn(u32Id < u32Limit, STATUS_INVALID_PARAMETER);
    136 
    137     /* Clear the corresponding bit. */
    138     ASMBitClear(pu32Bits, (int32_t)u32Id);
    139 
    140     return STATUS_SUCCESS;
    141 }
    142 
    143 
    144 DECLINLINE(void) gaFenceObjectsLock(VBOXWDDM_EXT_GA *pGaDevExt)
    145 {
    146     KeAcquireSpinLock(&pGaDevExt->fenceObjects.SpinLock, &pGaDevExt->fenceObjects.OldIrql);
    147 }
    148 
    149 DECLINLINE(void) gaFenceObjectsUnlock(VBOXWDDM_EXT_GA *pGaDevExt)
    150 {
    151     KeReleaseSpinLock(&pGaDevExt->fenceObjects.SpinLock, pGaDevExt->fenceObjects.OldIrql);
    152 }
    153 
    154 static void gaFenceObjectsDestroy(VBOXWDDM_EXT_GA *pGaDevExt,
    155                                   PVBOXWDDM_DEVICE pDevice)
     29void GaFenceObjectsDestroy(VBOXWDDM_EXT_GA *pGaDevExt,
     30                           PVBOXWDDM_DEVICE pDevice)
    15631{
    15732    RTLISTANCHOR list;
     
    228103}
    229104
    230 DECLINLINE(void) gaFenceUnrefLocked(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
     105void GaFenceUnrefLocked(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
    231106{
    232107    uint32_t c = ASMAtomicDecU32(&pFO->cRefs);
     
    238113}
    239114
    240 static GAFENCEOBJECT *gaFenceLookup(VBOXWDDM_EXT_GA *pGaDevExt,
    241                                     uint32_t u32FenceHandle)
     115GAFENCEOBJECT *GaFenceLookup(VBOXWDDM_EXT_GA *pGaDevExt,
     116                             uint32_t u32FenceHandle)
    242117{
    243118    /* Must be called under the fence object lock. */
     
    253128    return NULL;
    254129}
    255 
    256 
    257 void GaAdapterStop(PVBOXMP_DEVEXT pDevExt)
    258 {
    259     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    260     GALOG(("pDevExt = %p, pDevExt->pGa = %p\n", pDevExt, pGaDevExt));
    261 
    262     if (pGaDevExt)
    263     {
    264         /* Free fence objects. */
    265         gaFenceObjectsDestroy(pGaDevExt, NULL);
    266 
    267         if (pGaDevExt->hw.pSvga)
    268         {
    269             SvgaAdapterStop(pGaDevExt->hw.pSvga, &pDevExt->u.primary.DxgkInterface);
    270             pGaDevExt->hw.pSvga = NULL;
    271         }
    272 
    273         GaMemFree(pGaDevExt);
    274         pDevExt->pGa = NULL;
    275     }
    276 }
    277 
    278 NTSTATUS GaAdapterStart(PVBOXMP_DEVEXT pDevExt)
    279 {
    280     GALOG(("pDevExt = %p\n", pDevExt));
    281 
    282     NTSTATUS Status;
    283 
    284     if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
    285     {
    286         VBOXWDDM_EXT_GA *pGaDevExt = (VBOXWDDM_EXT_GA *)GaMemAllocZero(sizeof(*pGaDevExt));
    287         if (pGaDevExt)
    288         {
    289             /* Init fence objects. */
    290             pGaDevExt->fenceObjects.u32SeqNoSource = 0;
    291             RTListInit(&pGaDevExt->fenceObjects.list);
    292 
    293             KeInitializeSpinLock(&pGaDevExt->fenceObjects.SpinLock);
    294             RT_ZERO(pGaDevExt->fenceObjects.au32HandleBits);
    295             ASMBitSet(pGaDevExt->fenceObjects.au32HandleBits, 0); /* Exclude id==0, it is for NULL. */
    296 
    297             /* Start hardware. */
    298             Status = SvgaAdapterStart(&pGaDevExt->hw.pSvga, &pDevExt->u.primary.DxgkInterface,
    299                                       pDevExt->HwResources.phFIFO, pDevExt->HwResources.cbFIFO,
    300                                       pDevExt->HwResources.phIO, pDevExt->HwResources.cbIO);
    301             if (Status == STATUS_SUCCESS)
    302             {
    303                 pDevExt->pGa = pGaDevExt;
    304             }
    305         }
    306         else
    307         {
    308             Status = STATUS_INSUFFICIENT_RESOURCES;
    309         }
    310     }
    311     else
    312     {
    313         Status = STATUS_NOT_SUPPORTED;
    314     }
    315 
    316     if (Status != STATUS_SUCCESS)
    317     {
    318         GaAdapterStop(pDevExt);
    319     }
    320 
    321     return Status;
    322 }
    323 
    324 NTSTATUS GaQueryInfo(PVBOXWDDM_EXT_GA pGaDevExt,
    325                      VBOXVIDEO_HWTYPE enmHwType,
    326                      VBOXGAHWINFO *pHWInfo)
    327 {
    328     NTSTATUS Status = STATUS_SUCCESS;
    329 
    330     switch (enmHwType)
    331     {
    332         case VBOXVIDEO_HWTYPE_VMSVGA:
    333             pHWInfo->u32HwType = VBOX_GA_HW_TYPE_VMSVGA;
    334             break;
    335         default:
    336             Status = STATUS_NOT_SUPPORTED;
    337     }
    338 
    339     if (NT_SUCCESS(Status))
    340     {
    341         pHWInfo->u32Reserved = 0;
    342         RT_ZERO(pHWInfo->u.au8Raw);
    343 
    344         if (pHWInfo->u32HwType == VBOX_GA_HW_TYPE_VMSVGA)
    345         {
    346             Status = SvgaQueryInfo(pGaDevExt->hw.pSvga, &pHWInfo->u.svga);
    347         }
    348         else
    349         {
    350             Status = STATUS_NOT_SUPPORTED;
    351         }
    352     }
    353 
    354     return Status;
    355 }
    356 
    357 NTSTATUS GaDeviceCreate(PVBOXWDDM_EXT_GA pGaDevExt,
    358                         PVBOXWDDM_DEVICE pDevice)
    359 {
    360     RT_NOREF2(pGaDevExt, pDevice);
    361     return STATUS_SUCCESS;
    362 }
    363 
    364 void GaDeviceDestroy(PVBOXWDDM_EXT_GA pGaDevExt,
    365                      PVBOXWDDM_DEVICE pDevice)
    366 {
    367     /* Free fence objects and GMRs. This is useful when the application has crashed.. */
    368     gaFenceObjectsDestroy(pGaDevExt, pDevice);
    369     SvgaRegionsDestroy(pGaDevExt->hw.pSvga, pDevice);
    370 }
    371 
    372 NTSTATUS GaContextCreate(PVBOXWDDM_EXT_GA pGaDevExt,
    373                          PVBOXWDDM_CREATECONTEXT_INFO pInfo,
    374                          PVBOXWDDM_CONTEXT pContext)
    375 {
    376     AssertReturn(pContext->NodeOrdinal == 0, STATUS_NOT_SUPPORTED);
    377 
    378     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    379     uint32_t u32Cid;
    380     NTSTATUS Status = SvgaContextIdAlloc(pSvga, &u32Cid);
    381     if (NT_SUCCESS(Status))
    382     {
    383         Status = SvgaContextCreate(pSvga, u32Cid);
    384         if (Status == STATUS_SUCCESS)
    385         {
    386             /** @todo Save other pInfo fields. */
    387             RT_NOREF(pInfo);
    388 
    389             /* Init pContext fields, which are relevant to the gallium context. */
    390             pContext->u32Cid = u32Cid;
    391 
    392             GALOG(("pGaDevExt = %p, cid = %d\n", pGaDevExt, u32Cid));
    393         }
    394         else
    395         {
    396             SvgaContextIdFree(pSvga, u32Cid);
    397         }
    398     }
    399 
    400     return Status;
    401 }
    402 
    403 NTSTATUS GaContextDestroy(PVBOXWDDM_EXT_GA pGaDevExt,
    404                           PVBOXWDDM_CONTEXT pContext)
    405 {
    406     GALOG(("u32Cid = %d\n", pContext->u32Cid));
    407 
    408     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    409 
    410     SvgaContextDestroy(pSvga, pContext->u32Cid);
    411 
    412     return SvgaContextIdFree(pSvga, pContext->u32Cid);
    413 }
    414 
    415 NTSTATUS GaUpdate(PVBOXWDDM_EXT_GA pGaDevExt,
    416                   uint32_t u32X,
    417                   uint32_t u32Y,
    418                   uint32_t u32Width,
    419                   uint32_t u32Height)
    420 {
    421     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    422     return SvgaUpdate(pSvga, u32X, u32Y, u32Width, u32Height);
    423 }
    424 
    425 static NTSTATUS gaSurfaceDefine(PVBOXWDDM_EXT_GA pGaDevExt,
    426                                 GASURFCREATE *pCreateParms,
    427                                 GASURFSIZE *paSizes,
    428                                 uint32_t cSizes,
    429                                 uint32_t *pu32Sid)
    430 {
    431     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    432 
    433     uint32_t u32Sid;
    434     NTSTATUS Status = SvgaSurfaceIdAlloc(pSvga, &u32Sid);
    435     if (NT_SUCCESS(Status))
    436     {
    437         Status = SvgaSurfaceDefine(pSvga, pCreateParms, paSizes, cSizes, u32Sid);
    438         if (NT_SUCCESS(Status))
    439         {
    440             *pu32Sid = u32Sid;
    441         }
    442         else
    443         {
    444             SvgaSurfaceIdFree(pSvga, u32Sid);
    445         }
    446     }
    447     else
    448     {
    449         Status = STATUS_INSUFFICIENT_RESOURCES;
    450     }
    451 
    452     return Status;
    453 }
    454 
    455 static NTSTATUS gaSurfaceDestroy(PVBOXWDDM_EXT_GA pGaDevExt,
    456                                  uint32_t u32Sid)
    457 {
    458     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    459 
    460     NTSTATUS Status = SvgaSurfaceDestroy(pSvga, u32Sid);
    461     if (NT_SUCCESS(Status))
    462     {
    463         SvgaSurfaceIdFree(pSvga, u32Sid);
    464     }
    465 
    466     return Status;
    467 }
    468 
    469 NTSTATUS GaScreenDefine(PVBOXWDDM_EXT_GA pGaDevExt,
    470                         uint32_t u32Offset,
    471                         uint32_t u32ScreenId,
    472                         int32_t xOrigin,
    473                         int32_t yOrigin,
    474                         uint32_t u32Width,
    475                         uint32_t u32Height,
    476                         bool fBlank)
    477 {
    478     return SvgaScreenDefine(pGaDevExt->hw.pSvga, u32Offset, u32ScreenId, xOrigin, yOrigin, u32Width, u32Height, fBlank);
    479 }
    480 
    481 NTSTATUS GaScreenDestroy(PVBOXWDDM_EXT_GA pGaDevExt,
    482                          uint32_t u32ScreenId)
    483 {
    484     return SvgaScreenDestroy(pGaDevExt->hw.pSvga, u32ScreenId);
    485 }
    486 
    487 static NTSTATUS gaSharedSidInsert(PVBOXWDDM_EXT_GA pGaDevExt,
    488                                   uint32_t u32Sid,
    489                                   uint32_t u32SharedSid)
    490 {
    491     GASHAREDSID *pNode = (GASHAREDSID *)GaMemAllocZero(sizeof(GASHAREDSID));
    492     if (!pNode)
    493         return STATUS_INSUFFICIENT_RESOURCES;
    494     return SvgaSharedSidInsert(pGaDevExt->hw.pSvga, pNode, u32Sid, u32SharedSid);
    495 }
    496 
    497 static NTSTATUS gaSharedSidRemove(PVBOXWDDM_EXT_GA pGaDevExt,
    498                                   uint32_t u32Sid)
    499 {
    500     GASHAREDSID *pNode = SvgaSharedSidRemove(pGaDevExt->hw.pSvga, u32Sid);
    501     if (pNode)
    502         GaMemFree(pNode);
    503     return STATUS_SUCCESS;
    504 }
    505 
    506130
    507131/*
     
    556180    gaFenceObjectsLock(pGaDevExt);
    557181
    558     GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
     182    GAFENCEOBJECT *pFO = GaFenceLookup(pGaDevExt, u32FenceHandle);
    559183
    560184    gaFenceObjectsUnlock(pGaDevExt);
     
    592216    gaFenceObjectsLock(pGaDevExt);
    593217
    594     GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
     218    GAFENCEOBJECT *pFO = GaFenceLookup(pGaDevExt, u32FenceHandle);
    595219    AssertReturnStmt(pFO, gaFenceObjectsUnlock(pGaDevExt), STATUS_INVALID_PARAMETER);
    596220
     
    629253    gaFenceObjectsLock(pGaDevExt);
    630254
    631     GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
     255    GAFENCEOBJECT *pFO = GaFenceLookup(pGaDevExt, u32FenceHandle);
    632256    AssertReturnStmt(pFO, gaFenceObjectsUnlock(pGaDevExt), STATUS_INVALID_PARAMETER);
    633257
     
    642266    GALOG(("u32FenceHandle = %d, pFO %p\n", u32FenceHandle, pFO));
    643267
    644     /* Undo gaFenceLookup ref. */
     268    /* Undo GaFenceLookup ref. */
    645269    gaFenceUnref(pGaDevExt, pFO);
    646270
     
    650274    return STATUS_SUCCESS;
    651275}
    652 
    653 static NTSTATUS gaPresent(PVBOXWDDM_EXT_GA pGaDevExt,
    654                           uint32_t u32Sid,
    655                           uint32_t u32Width,
    656                           uint32_t u32Height,
    657                           uint32_t u32VRAMOffset)
    658 {
    659     return SvgaPresentVRAM(pGaDevExt->hw.pSvga, u32Sid, u32Width, u32Height, u32VRAMOffset);
    660 }
    661 
    662 static int gaFenceCmp(uint32_t u32FenceA, uint32_t u32FenceB)
    663 {
    664      if (   u32FenceA < u32FenceB
    665          || u32FenceA - u32FenceB > UINT32_MAX / 2)
    666      {
    667          return -1; /* FenceA is newer than FenceB. */
    668      }
    669      else if (u32FenceA == u32FenceB)
    670      {
    671          /* FenceA is equal to FenceB. */
    672          return 0;
    673      }
    674 
    675      /* FenceA is older than FenceB. */
    676      return 1;
    677 }
    678 
    679 
    680 static void dxgkNotifyDma(DXGKRNL_INTERFACE *pDxgkInterface,
    681                           DXGK_INTERRUPT_TYPE enmType,
    682                           UINT uNodeOrdinal,
    683                           UINT uFenceId,
    684                           UINT uLastCompletedFenceId)
    685 {
    686     DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
    687     memset(&notify, 0, sizeof(notify));
    688 
    689     GALOG(("%d fence %d\n", enmType, uFenceId));
    690     switch (enmType)
    691     {
    692         case DXGK_INTERRUPT_DMA_COMPLETED:
    693             notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
    694             notify.DmaCompleted.SubmissionFenceId = uFenceId;
    695             notify.DmaCompleted.NodeOrdinal = uNodeOrdinal;
    696             break;
    697 
    698         case DXGK_INTERRUPT_DMA_PREEMPTED:
    699             notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
    700             notify.DmaPreempted.PreemptionFenceId = uFenceId;
    701             notify.DmaPreempted.NodeOrdinal = uNodeOrdinal;
    702             notify.DmaPreempted.LastCompletedFenceId = uLastCompletedFenceId;
    703             break;
    704 
    705         case DXGK_INTERRUPT_DMA_FAULTED:
    706             notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
    707             notify.DmaFaulted.FaultedFenceId = uFenceId;
    708             notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL;
    709             notify.DmaFaulted.NodeOrdinal = uNodeOrdinal;
    710             break;
    711 
    712         default:
    713             WARN(("completion type %d", enmType));
    714             break;
    715     }
    716 
    717     if (notify.InterruptType)
    718     {
    719         pDxgkInterface->DxgkCbNotifyInterrupt(pDxgkInterface->DeviceHandle, &notify);
    720         GALOG(("notified\n"));
    721     }
    722 }
    723 
    724 static void gaReportFence(PVBOXMP_DEVEXT pDevExt)
    725 {
    726     /* Runs at device interrupt IRQL. */
    727     Assert(KeGetCurrentIrql() > DISPATCH_LEVEL);
    728 
    729     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    730     AssertReturnVoid(pGaDevExt);
    731 
    732     PVBOXWDDM_EXT_VMSVGA pSvga = pGaDevExt->hw.pSvga;
    733     AssertReturnVoid(pSvga);
    734 
    735     /* Read the last completed fence from the device. */
    736     const uint32_t u32Fence = SVGAFifoRead(pSvga, SVGA_FIFO_FENCE);
    737     GALOG(("Fence %u\n", u32Fence));
    738 
    739     if (u32Fence == ASMAtomicReadU32(&pGaDevExt->u32PreemptionFenceId))
    740     {
    741         ASMAtomicWriteU32(&pGaDevExt->u32PreemptionFenceId, 0);
    742 
    743         const uint32_t u32LastSubmittedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastSubmittedFenceId);
    744         ASMAtomicWriteU32(&pGaDevExt->u32LastCompletedFenceId, u32LastSubmittedFenceId);
    745 
    746         dxgkNotifyDma(&pDevExt->u.primary.DxgkInterface, DXGK_INTERRUPT_DMA_PREEMPTED,
    747                       0, u32Fence, u32LastSubmittedFenceId);
    748 
    749         /* Notify DXGK about the updated DMA fence. */
    750         pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
    751     }
    752     else
    753     {
    754         /* Check if we already reported it. */
    755         const uint32_t u32LastCompletedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedFenceId);
    756         if (gaFenceCmp(u32LastCompletedFenceId, u32Fence) < 0)
    757         {
    758             /* u32Fence is newer. */
    759             ASMAtomicWriteU32(&pGaDevExt->u32LastCompletedFenceId, u32Fence);
    760 
    761             dxgkNotifyDma(&pDevExt->u.primary.DxgkInterface, DXGK_INTERRUPT_DMA_COMPLETED,
    762                           0, u32Fence, u32Fence);
    763 
    764             /* Notify DXGK about the updated DMA fence. */
    765             pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
    766         }
    767     }
    768 }
    769 
    770 /*
    771  * Description of DMA buffer content.
    772  * These structures are stored in DmaBufferPrivateData.
    773  */
    774 typedef struct GARENDERDATA
    775 {
    776     uint32_t      u32DataType;    /* GARENDERDATA_TYPE_* */
    777     uint32_t      cbData;         /* How many bytes. */
    778     GAFENCEOBJECT *pFenceObject;  /* User mode fence associated with this command buffer. */
    779     void          *pvDmaBuffer;   /* Pointer to the DMA buffer. */
    780 } GARENDERDATA;
    781 
    782 #define GARENDERDATA_TYPE_RENDER   1
    783 #define GARENDERDATA_TYPE_PRESENT  2
    784 #define GARENDERDATA_TYPE_PAGING   3
    785 #define GARENDERDATA_TYPE_FENCE    4
    786 
    787 /* If there are no commands but we need to trigger fence submission anyway, then submit a buffer of this size. */
    788 #define GA_DMA_MIN_SUBMIT_SIZE 4
    789 AssertCompile(GA_DMA_MIN_SUBMIT_SIZE < sizeof(SVGA3dCmdHeader));
    790 
    791 DECLINLINE(PVBOXWDDM_ALLOCATION) vboxWddmGetAllocationFromAllocList(DXGK_ALLOCATIONLIST *pAllocList)
    792 {
    793     PVBOXWDDM_OPENALLOCATION pOa = (PVBOXWDDM_OPENALLOCATION)pAllocList->hDeviceSpecificAllocation;
    794     return pOa? pOa->pAllocation: NULL;
    795 }
    796 
    797 static NTSTATUS gaGMRFBToVRAMSurface(DXGKARG_PRESENT *pPresent,
    798                                      PVBOXWDDM_EXT_VMSVGA pSvga,
    799                                      uint32_t idxAllocation,
    800                                      DXGK_ALLOCATIONLIST *pAllocationList,
    801                                      PVBOXWDDM_ALLOCATION pAllocation,
    802                                      uint8_t *pu8Target, uint32_t cbTarget, uint32_t *pu32TargetOut)
    803 {
    804     NTSTATUS Status = SvgaGenDefineGMRFB(pSvga,
    805                                          pAllocationList->SegmentId != 0 ?
    806                                              pAllocationList->PhysicalAddress.LowPart : 0,
    807                                          pAllocation->AllocData.SurfDesc.pitch,
    808                                          pu8Target, cbTarget, pu32TargetOut);
    809     if (Status == STATUS_SUCCESS)
    810     {
    811         /* Always tell WDDM that the SHADOWSURFACE must be "paged in". */
    812         UINT PatchOffset =   (uintptr_t)pu8Target - (uintptr_t)pPresent->pDmaBuffer
    813                            + sizeof(uint32_t)
    814                            + RT_UOFFSETOF(SVGAFifoCmdDefineGMRFB, ptr.offset);
    815 
    816         memset(pPresent->pPatchLocationListOut, 0, sizeof(D3DDDI_PATCHLOCATIONLIST));
    817         pPresent->pPatchLocationListOut->AllocationIndex = idxAllocation;
    818         pPresent->pPatchLocationListOut->PatchOffset = PatchOffset;
    819         ++pPresent->pPatchLocationListOut;
    820     }
    821     return Status;
    822 }
    823 
    824 /** Generate commands for Blt case.
    825  *
    826  * @return Status code.
    827  * @param pPresent          Information about rectangles to blit.
    828  * @param pSvga             VMSVGA device extension.
    829  * @param pSrc              Source allocation description.
    830  * @param pSrcAlloc         Allocation to blit from.
    831  * @param pDst              Destination allocation description.
    832  * @param pDstAlloc         Allocation to blit to.
    833  * @param pu8Target         Command buffer to fill.
    834  * @param cbTarget          Size of command buffer.
    835  * @param pu32TargetOut     Where to store size of generated commands.
    836  */
    837 static NTSTATUS gaPresentBlt(DXGKARG_PRESENT *pPresent,
    838                              PVBOXWDDM_EXT_VMSVGA pSvga,
    839                              DXGK_ALLOCATIONLIST *pSrc,
    840                              PVBOXWDDM_ALLOCATION pSrcAlloc,
    841                              DXGK_ALLOCATIONLIST *pDst,
    842                              PVBOXWDDM_ALLOCATION pDstAlloc,
    843                              uint8_t *pu8Target, uint32_t cbTarget, uint32_t *pu32TargetOut)
    844 {
    845     NTSTATUS Status = STATUS_SUCCESS;
    846 
    847     uint8_t * const pu8TargetStart = pu8Target;
    848 
    849     uint32_t cbCmd = 0;
    850 
    851     /** @todo One subrect at a time for now, consider passing all pDstSubRects when possible,
    852      * for example in one BlitSurfaceToScreen.
    853      */
    854     uint32_t iSubRect;
    855     for (iSubRect = pPresent->MultipassOffset; iSubRect < pPresent->SubRectCnt; ++iSubRect)
    856     {
    857         /* DstSubRects are in Dst coords.
    858          * To calculate corresponding SrcSubRect:
    859          *    srcsub = src + (dstsub - dst) = dstsub + (src - dst).
    860          * Precompute the src - dst differences to use in the code below.
    861          */
    862         int32_t const dx = pPresent->SrcRect.left - pPresent->DstRect.left;
    863         int32_t const dy = pPresent->SrcRect.top  - pPresent->DstRect.top;
    864 
    865         if (iSubRect == 0)
    866         {
    867             if (   pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
    868                 || pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE)
    869             {
    870                 /* Define GMRFB to point to the shadow/staging surface. */
    871                 Status = gaGMRFBToVRAMSurface(pPresent, pSvga,
    872                                               DXGK_PRESENT_SOURCE_INDEX, pSrc, pSrcAlloc,
    873                                               pu8Target, cbTarget, &cbCmd);
    874             }
    875             else if (   pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
    876                      || pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE)
    877             {
    878                 /* Define GMRFB to point to the shadow/staging surface. */
    879                 Status = gaGMRFBToVRAMSurface(pPresent, pSvga,
    880                                               DXGK_PRESENT_DESTINATION_INDEX, pDst, pDstAlloc,
    881                                               pu8Target, cbTarget, &cbCmd);
    882             }
    883 
    884             if (Status == STATUS_BUFFER_OVERFLOW)
    885             {
    886                 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    887                 break;
    888             }
    889 
    890             pu8Target += cbCmd;
    891             cbTarget -= cbCmd;
    892         }
    893 
    894         if (pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE)
    895         {
    896             /* To screen. */
    897             if (   pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
    898                 || pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE)
    899             {
    900                 /* From GDI software drawing surface. */
    901                 GALOG(("Blt: SHADOWSURFACE(%d) 0x%08X -> SHAREDPRIMARYSURFACE 0x%08X\n",
    902                        pSrcAlloc->enmType, pSrc->PhysicalAddress.LowPart, pDst->PhysicalAddress.LowPart));
    903 
    904                 int32_t const xSrc = pPresent->pDstSubRects[iSubRect].left + dx;
    905                 int32_t const ySrc = pPresent->pDstSubRects[iSubRect].top  + dy;
    906                 Status = SvgaGenBlitGMRFBToScreen(pSvga,
    907                                                   pDstAlloc->AllocData.SurfDesc.VidPnSourceId,
    908                                                   xSrc, ySrc,
    909                                                   &pPresent->pDstSubRects[iSubRect],
    910                                                   pu8Target, cbTarget, &cbCmd);
    911             }
    912             else if (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC)
    913             {
    914                 /* From a surface. */
    915                 GALOG(("Blt: surface id 0x%08X -> SHAREDPRIMARYSURFACE 0x%08X\n",
    916                        pSrcAlloc->AllocData.hostID, pDst->PhysicalAddress.LowPart));
    917 
    918                 RECT const dstRect = pPresent->pDstSubRects[iSubRect];
    919                 RECT srcRect;
    920                 srcRect.left   = dstRect.left   + dx;
    921                 srcRect.top    = dstRect.top    + dy;
    922                 srcRect.right  = dstRect.right  + dx;
    923                 srcRect.bottom = dstRect.bottom + dy;
    924                 RECT clipRect = dstRect;
    925                 Status = SvgaGenBlitSurfaceToScreen(pSvga,
    926                                                     pSrcAlloc->AllocData.hostID,
    927                                                     &srcRect,
    928                                                     pDstAlloc->AllocData.SurfDesc.VidPnSourceId,
    929                                                     &dstRect,
    930                                                     1, &clipRect,
    931                                                     pu8Target, cbTarget, &cbCmd, NULL);
    932             }
    933             else
    934             {
    935                 AssertFailed();
    936             }
    937         }
    938         else if (  pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
    939                 || pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE)
    940         {
    941             /* To GDI software drawing surface. */
    942             if (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE)
    943             {
    944                 /* From screen. */
    945                 GALOG(("Blt: SHAREDPRIMARYSURFACE 0x%08X -> SHADOWSURFACE(%d) 0x%08X\n",
    946                        pSrc->PhysicalAddress.LowPart, pDstAlloc->enmType, pDst->PhysicalAddress.LowPart));
    947 
    948                 int32_t const xSrc = pPresent->pDstSubRects[iSubRect].left + dx;
    949                 int32_t const ySrc = pPresent->pDstSubRects[iSubRect].top  + dy;
    950 
    951                 Status = SvgaGenBlitScreenToGMRFB(pSvga,
    952                                                   pSrcAlloc->AllocData.SurfDesc.VidPnSourceId,
    953                                                   xSrc, ySrc,
    954                                                   &pPresent->pDstSubRects[iSubRect],
    955                                                   pu8Target, cbTarget, &cbCmd);
    956             }
    957             else if (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC)
    958             {
    959                 /* From a surface. */
    960                 GALOG(("Blt: surface id 0x%08X -> SHADOWSURFACE(%d) %d:0x%08X\n",
    961                        pSrcAlloc->AllocData.hostID, pDstAlloc->enmType, pDst->SegmentId, pDst->PhysicalAddress.LowPart));
    962 
    963                 SVGAGuestImage guestImage;
    964                 guestImage.ptr.gmrId  = SVGA_GMR_FRAMEBUFFER;
    965                 guestImage.ptr.offset = pDst->SegmentId != 0 ?  pDst->PhysicalAddress.LowPart : 0;
    966                 guestImage.pitch      = pDstAlloc->AllocData.SurfDesc.pitch;
    967 
    968                 SVGA3dSurfaceImageId surfId;
    969                 surfId.sid    = pSrcAlloc->AllocData.hostID;
    970                 surfId.face   = 0;
    971                 surfId.mipmap = 0;
    972 
    973                 int32_t const xSrc = pPresent->pDstSubRects[iSubRect].left + dx;
    974                 int32_t const ySrc = pPresent->pDstSubRects[iSubRect].top  + dy;
    975 
    976                 Status = SvgaGenSurfaceDMA(pSvga,
    977                                            &guestImage, &surfId, SVGA3D_READ_HOST_VRAM,
    978                                            xSrc, ySrc,
    979                                            pPresent->pDstSubRects[iSubRect].left,
    980                                            pPresent->pDstSubRects[iSubRect].top,
    981                                            pPresent->pDstSubRects[iSubRect].right - pPresent->pDstSubRects[iSubRect].left,
    982                                            pPresent->pDstSubRects[iSubRect].bottom - pPresent->pDstSubRects[iSubRect].top,
    983                                            pu8Target, cbTarget, &cbCmd);
    984                 if (Status == STATUS_SUCCESS)
    985                 {
    986                     /* Always tell WDDM that the SHADOWSURFACE must be "paged in". */
    987                     UINT PatchOffset =   (uintptr_t)pu8Target - (uintptr_t)pPresent->pDmaBuffer
    988                                        + sizeof(SVGA3dCmdHeader)
    989                                        + RT_UOFFSETOF(SVGA3dCmdSurfaceDMA, guest.ptr.offset);
    990 
    991                     memset(pPresent->pPatchLocationListOut, 0, sizeof(D3DDDI_PATCHLOCATIONLIST));
    992                     pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX;
    993                     pPresent->pPatchLocationListOut->PatchOffset = PatchOffset;
    994                     ++pPresent->pPatchLocationListOut;
    995                 }
    996             }
    997             else
    998             {
    999                 AssertFailed();
    1000             }
    1001         }
    1002         else
    1003             AssertFailed();
    1004 
    1005         if (Status == STATUS_BUFFER_OVERFLOW)
    1006         {
    1007             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1008             break;
    1009         }
    1010 
    1011         pu8Target += cbCmd;
    1012         cbTarget -= cbCmd;
    1013     }
    1014 
    1015     *pu32TargetOut = (uintptr_t)pu8Target - (uintptr_t)pu8TargetStart;
    1016 
    1017     if (Status == STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER)
    1018     {
    1019         pPresent->MultipassOffset = iSubRect;
    1020     }
    1021 
    1022     return Status;
    1023 }
    1024 
    1025 NTSTATUS APIENTRY GaDxgkDdiPresent(const HANDLE hContext,
    1026                                    DXGKARG_PRESENT *pPresent)
    1027 {
    1028     NTSTATUS Status = STATUS_SUCCESS;
    1029     PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
    1030     PVBOXWDDM_DEVICE pDevice = pContext->pDevice;
    1031     PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
    1032 
    1033     DXGK_ALLOCATIONLIST *pSrc =  &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX];
    1034     DXGK_ALLOCATIONLIST *pDst =  &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX];
    1035 
    1036     if (pPresent->Flags.Blt)
    1037     {
    1038         PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pSrc);
    1039         PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDst);
    1040 
    1041         GALOG(("Blt: sid=%x -> sid=%x\n", pSrcAlloc->AllocData.hostID, pDstAlloc->AllocData.hostID));
    1042 
    1043         /** @todo Review standard allocations (DxgkDdiGetStandardAllocationDriverData, etc).
    1044          *        Probably can be used more naturally with VMSVGA.
    1045          */
    1046 
    1047         /** @todo Merge common code for all branches (Blt, Flip, ColorFill) */
    1048 
    1049         /* Generate DMA buffer containing the SVGA_CMD_BLIT_GMRFB_TO_SCREEN commands.
    1050          * Store the command buffer descriptor to pDmaBufferPrivateData.
    1051          */
    1052         GARENDERDATA *pRenderData = NULL;
    1053         uint32_t u32TargetLength = 0;
    1054         uint32_t cbPrivateData = 0;
    1055 
    1056         if (pPresent->DmaBufferPrivateDataSize >= sizeof(GARENDERDATA))
    1057         {
    1058             uint8_t *pu8Target = (uint8_t *)pPresent->pDmaBuffer;
    1059             uint32_t cbTarget = pPresent->DmaSize;
    1060 
    1061             Status = gaPresentBlt(pPresent, pDevExt->pGa->hw.pSvga, pSrc, pSrcAlloc, pDst, pDstAlloc,
    1062                                   pu8Target, cbTarget, &u32TargetLength);
    1063 
    1064             /* Fill RenderData description in any case, it will be ignored if the above code failed. */
    1065             pRenderData = (GARENDERDATA *)pPresent->pDmaBufferPrivateData;
    1066             pRenderData->u32DataType  = GARENDERDATA_TYPE_PRESENT;
    1067             pRenderData->cbData       = u32TargetLength;
    1068             pRenderData->pFenceObject = NULL; /* Not a user request, so no user accessible fence object. */
    1069             pRenderData->pvDmaBuffer  = pPresent->pDmaBuffer;
    1070             cbPrivateData = sizeof(GARENDERDATA);
    1071         }
    1072         else
    1073         {
    1074             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1075         }
    1076 
    1077         switch (Status)
    1078         {
    1079             case STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER:
    1080                 if (pRenderData == NULL)
    1081                 {
    1082                     /* Not enough space in pDmaBufferPrivateData. */
    1083                     break;
    1084                 }
    1085                 RT_FALL_THRU();
    1086             case STATUS_SUCCESS:
    1087             {
    1088                 if (u32TargetLength)
    1089                 {
    1090                     pPresent->pDmaBuffer = (uint8_t *)pPresent->pDmaBuffer + u32TargetLength;
    1091                     pPresent->pDmaBufferPrivateData = (uint8_t *)pPresent->pDmaBufferPrivateData + cbPrivateData;
    1092                 }
    1093             } break;
    1094             default: break;
    1095         }
    1096     }
    1097     else if (pPresent->Flags.Flip)
    1098     {
    1099         PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pSrc);
    1100 
    1101         GALOG(("Flip: sid=%x %dx%d\n",
    1102                pSrcAlloc->AllocData.hostID, pSrcAlloc->AllocData.SurfDesc.width, pSrcAlloc->AllocData.SurfDesc.height));
    1103 
    1104         GALOG(("Flip: %d,%d %d,%d -> %d,%d %d,%d subrects %d\n",
    1105                pPresent->SrcRect.left, pPresent->SrcRect.top, pPresent->SrcRect.right, pPresent->SrcRect.bottom,
    1106                pPresent->DstRect.left, pPresent->DstRect.top, pPresent->DstRect.right, pPresent->DstRect.bottom,
    1107                pPresent->SubRectCnt));
    1108         uint32_t iSubRect;
    1109         for (iSubRect = 0; iSubRect < pPresent->SubRectCnt; ++iSubRect)
    1110         {
    1111             GALOG(("Flip[%d]: %d,%d %d,%d\n",
    1112                    pPresent->pDstSubRects[iSubRect].left, pPresent->pDstSubRects[iSubRect].top,
    1113                    pPresent->pDstSubRects[iSubRect].right, pPresent->pDstSubRects[iSubRect].bottom,
    1114                    iSubRect));
    1115         }
    1116 
    1117         /* Generate DMA buffer containing the present commands.
    1118          * Store the command buffer descriptor to pDmaBufferPrivateData.
    1119          */
    1120         GARENDERDATA *pRenderData = NULL;
    1121         uint32_t u32TargetLength = 0;
    1122         uint32_t cbPrivateData = 0;
    1123 
    1124         if (pPresent->DmaBufferPrivateDataSize >= sizeof(GARENDERDATA))
    1125         {
    1126             void *pvTarget          = pPresent->pDmaBuffer;
    1127             const uint32_t cbTarget = pPresent->DmaSize;
    1128             if (cbTarget > GA_DMA_MIN_SUBMIT_SIZE)
    1129             {
    1130 #if 1
    1131                 /* SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN */
    1132                 RECT rect;
    1133                 rect.left   = 0;
    1134                 rect.top    = 0;
    1135                 rect.right  = pSrcAlloc->AllocData.SurfDesc.width;
    1136                 rect.bottom = pSrcAlloc->AllocData.SurfDesc.height;
    1137                 uint32_t const cInClipRects = pPresent->SubRectCnt - pPresent->MultipassOffset;
    1138                 uint32_t cOutClipRects = 0;
    1139                 Status = SvgaGenBlitSurfaceToScreen(pDevExt->pGa->hw.pSvga,
    1140                                                     pSrcAlloc->AllocData.hostID,
    1141                                                     &rect,
    1142                                                     pSrcAlloc->AllocData.SurfDesc.VidPnSourceId,
    1143                                                     &rect,
    1144                                                     cInClipRects,
    1145                                                     pPresent->pDstSubRects + pPresent->MultipassOffset,
    1146                                                     pvTarget, cbTarget, &u32TargetLength, &cOutClipRects);
    1147                 if (Status == STATUS_BUFFER_OVERFLOW)
    1148                 {
    1149                     Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1150                 }
    1151 
    1152                 if (Status == STATUS_SUCCESS)
    1153                 {
    1154                     if (cOutClipRects < cInClipRects)
    1155                     {
    1156                         /* Not all rectangles were copied. */
    1157                         Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1158                     }
    1159 
    1160                     /* Advance the current rectangle index. */
    1161                     pPresent->MultipassOffset += cOutClipRects;
    1162                 }
    1163 #else
    1164                 /* This tests the SVGA_3D_CMD_PRESENT command. */
    1165                 RT_NOREF(pDevExt);
    1166                 Status = SvgaGenPresent(pSrcAlloc->AllocData.hostID,
    1167                                         pSrcAlloc->AllocData.SurfDesc.width,
    1168                                         pSrcAlloc->AllocData.SurfDesc.height,
    1169                                         pvTarget, cbTarget, &u32TargetLength);
    1170                 if (Status == STATUS_BUFFER_OVERFLOW)
    1171                 {
    1172                     Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1173                 }
    1174 #endif
    1175             }
    1176             else
    1177             {
    1178                 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1179             }
    1180 
    1181             /* Fill RenderData description in any case, it will be ignored if the above code failed. */
    1182             pRenderData = (GARENDERDATA *)pPresent->pDmaBufferPrivateData;
    1183             pRenderData->u32DataType  = GARENDERDATA_TYPE_PRESENT;
    1184             pRenderData->cbData       = u32TargetLength;
    1185             pRenderData->pFenceObject = NULL; /* Not a user request, so no user accessible fence object. */
    1186             pRenderData->pvDmaBuffer = pPresent->pDmaBuffer;
    1187             cbPrivateData = sizeof(GARENDERDATA);
    1188         }
    1189         else
    1190         {
    1191             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1192         }
    1193 
    1194         switch (Status)
    1195         {
    1196             case STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER:
    1197                 if (pRenderData == NULL)
    1198                 {
    1199                     /* Not enough space in pDmaBufferPrivateData. */
    1200                     break;
    1201                 }
    1202                 RT_FALL_THRU();
    1203             case STATUS_SUCCESS:
    1204             {
    1205                 if (u32TargetLength)
    1206                 {
    1207                     pPresent->pDmaBuffer = (uint8_t *)pPresent->pDmaBuffer + u32TargetLength;
    1208                     pPresent->pDmaBufferPrivateData = (uint8_t *)pPresent->pDmaBufferPrivateData + cbPrivateData;
    1209                 }
    1210             } break;
    1211             default: break;
    1212         }
    1213     }
    1214     else if (pPresent->Flags.ColorFill)
    1215     {
    1216         GALOG(("ColorFill\n"));
    1217         AssertFailed();
    1218     }
    1219     else
    1220     {
    1221         WARN(("cmd NOT IMPLEMENTED!! Flags(0x%x)", pPresent->Flags.Value));
    1222         Status = STATUS_NOT_SUPPORTED;
    1223     }
    1224 
    1225     return Status;
    1226 }
    1227 
    1228 NTSTATUS APIENTRY GaDxgkDdiRender(const HANDLE hContext, DXGKARG_RENDER *pRender)
    1229 {
    1230     PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
    1231     PVBOXWDDM_DEVICE pDevice = pContext->pDevice;
    1232     PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
    1233     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1234 
    1235     AssertReturn(pContext && pContext->enmType == VBOXWDDM_CONTEXT_TYPE_GA_3D, STATUS_INVALID_PARAMETER);
    1236     AssertReturn(pRender->CommandLength > pRender->MultipassOffset, STATUS_INVALID_PARAMETER);
    1237     /* Expect 32 bit handle at the start of the command buffer. */
    1238     AssertReturn(pRender->CommandLength >= sizeof(uint32_t), STATUS_INVALID_PARAMETER);
    1239 
    1240     GARENDERDATA *pRenderData = NULL;  /* Pointer to the DMA buffer description. */
    1241     uint32_t cbPrivateData = 0;        /* Bytes to place into the private data buffer. */
    1242     uint32_t u32TargetLength = 0;      /* Bytes to place into the DMA buffer. */
    1243     uint32_t u32ProcessedLength = 0;   /* Bytes consumed from command buffer. */
    1244 
    1245     GALOG(("[%p] Command %p/%d, Dma %p/%d, Private %p/%d, MO %d, S %d, Phys 0x%RX64, AL %p/%d, PLLIn %p/%d, PLLOut %p/%d\n",
    1246            hContext,
    1247            pRender->pCommand, pRender->CommandLength,
    1248            pRender->pDmaBuffer, pRender->DmaSize,
    1249            pRender->pDmaBufferPrivateData, pRender->DmaBufferPrivateDataSize,
    1250            pRender->MultipassOffset, pRender->DmaBufferSegmentId, pRender->DmaBufferPhysicalAddress.QuadPart,
    1251            pRender->pAllocationList, pRender->AllocationListSize,
    1252            pRender->pPatchLocationListIn, pRender->PatchLocationListInSize,
    1253            pRender->pPatchLocationListOut, pRender->PatchLocationListOutSize
    1254          ));
    1255 
    1256     /* 32 bit handle at the start of the command buffer. */
    1257     if (pRender->MultipassOffset == 0)
    1258         pRender->MultipassOffset += sizeof(uint32_t);
    1259 
    1260     NTSTATUS Status = STATUS_SUCCESS;
    1261     __try
    1262     {
    1263         /* Calculate where the commands start. */
    1264         void const *pvSource = (uint8_t *)pRender->pCommand + pRender->MultipassOffset;
    1265         uint32_t cbSource = pRender->CommandLength - pRender->MultipassOffset;
    1266 
    1267         /* Generate DMA buffer from the supplied command buffer.
    1268          * Store the command buffer descriptor to pDmaBufferPrivateData.
    1269          *
    1270          * The display miniport driver must validate the command buffer.
    1271          *
    1272          * Copy commands to the pDmaBuffer.
    1273          * If a command uses a shared surface id, then replace the id with the original surface id.
    1274          */
    1275         if (pRender->DmaBufferPrivateDataSize >= sizeof(GARENDERDATA))
    1276         {
    1277             void *pvTarget          = pRender->pDmaBuffer;
    1278             uint32_t const cbTarget = pRender->DmaSize;
    1279             if (cbTarget > GA_DMA_MIN_SUBMIT_SIZE)
    1280             {
    1281                 Status = SvgaRenderCommands(pGaDevExt->hw.pSvga, pvTarget, cbTarget, pvSource, cbSource,
    1282                                             &u32TargetLength, &u32ProcessedLength);
    1283             }
    1284             else
    1285             {
    1286                 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1287             }
    1288 
    1289             GAFENCEOBJECT *pFO = NULL;
    1290             if (Status == STATUS_SUCCESS)
    1291             {
    1292                 /* Completed the command buffer. Check if there is a user mode fence. */
    1293                 uint32_t const u32FenceHandle = *(uint32_t *)pRender->pCommand;
    1294                 if (u32FenceHandle != 0)
    1295                 {
    1296                     /* Verify that the buffer handle is valid. */
    1297                     gaFenceObjectsLock(pGaDevExt);
    1298                     pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
    1299                     gaFenceObjectsUnlock(pGaDevExt);
    1300 
    1301                     if (!pFO) // Maybe silently ignore?
    1302                     {
    1303                         AssertFailed();
    1304                         Status = STATUS_INVALID_PARAMETER;
    1305                     }
    1306                 }
    1307 
    1308                 GALOG(("u32FenceHandle = %d, pFO = %p\n", u32FenceHandle, pFO));
    1309             }
    1310 
    1311             /* Fill RenderData description in any case, it will be ignored if the above code failed. */
    1312             pRenderData = (GARENDERDATA *)pRender->pDmaBufferPrivateData;
    1313             pRenderData->u32DataType  = GARENDERDATA_TYPE_RENDER;
    1314             pRenderData->cbData       = u32TargetLength;
    1315             pRenderData->pFenceObject = pFO;
    1316             pRenderData->pvDmaBuffer  = pRender->pDmaBuffer;
    1317             cbPrivateData = sizeof(GARENDERDATA);
    1318         }
    1319         else
    1320         {
    1321             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1322         }
    1323 
    1324         GALOG(("Status = 0x%x\n", Status));
    1325     }
    1326     __except (EXCEPTION_EXECUTE_HANDLER)
    1327     {
    1328         Status = STATUS_INVALID_PARAMETER;
    1329     }
    1330 
    1331     switch (Status)
    1332     {
    1333         case STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER:
    1334             pRender->MultipassOffset += u32ProcessedLength;
    1335             if (pRenderData == NULL)
    1336             {
    1337                 /* Not enough space in pDmaBufferPrivateData. */
    1338                 break;
    1339             }
    1340             RT_FALL_THRU();
    1341         case STATUS_SUCCESS:
    1342         {
    1343             Assert(pRenderData);
    1344             if (u32TargetLength == 0)
    1345             {
    1346                 /* Trigger command submission anyway by increasing pDmaBuffer */
    1347                 u32TargetLength = GA_DMA_MIN_SUBMIT_SIZE;
    1348 
    1349                 /* Update the DMA buffer description. */
    1350                 pRenderData->u32DataType  = GARENDERDATA_TYPE_FENCE;
    1351                 pRenderData->cbData       = u32TargetLength;
    1352                 /* pRenderData->pFenceObject stays */
    1353                 pRenderData->pvDmaBuffer  = NULL; /* Not used */
    1354             }
    1355             pRender->pDmaBuffer = (uint8_t *)pRender->pDmaBuffer + u32TargetLength;
    1356             pRender->pDmaBufferPrivateData = (uint8_t *)pRender->pDmaBufferPrivateData + cbPrivateData;
    1357         } break;
    1358         default: break;
    1359     }
    1360 
    1361     return Status;
    1362 }
    1363 
    1364 static NTSTATUS gaSoftwarePagingTransfer(PVBOXMP_DEVEXT pDevExt,
    1365                                          DXGKARG_BUILDPAGINGBUFFER *pBuildPagingBuffer)
    1366 {
    1367     RT_NOREF2(pDevExt, pBuildPagingBuffer);
    1368     /** @todo Implement.
    1369      * Do the SysMem <-> VRAM transfer in software, because
    1370      * the VMSVGA device does not have appropriate commands.
    1371      */
    1372     return STATUS_SUCCESS;
    1373 }
    1374 
    1375 NTSTATUS APIENTRY GaDxgkDdiBuildPagingBuffer(const HANDLE hAdapter,
    1376                                              DXGKARG_BUILDPAGINGBUFFER *pBuildPagingBuffer)
    1377 {
    1378     NTSTATUS Status = STATUS_SUCCESS;
    1379     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1380 
    1381     GALOG(("DmaBufferPrivateData %p/%d, DmaBuffer %p/%d\n",
    1382            pBuildPagingBuffer->pDmaBufferPrivateData,
    1383            pBuildPagingBuffer->DmaBufferPrivateDataSize,
    1384            pBuildPagingBuffer->pDmaBuffer,
    1385            pBuildPagingBuffer->DmaSize));
    1386 
    1387     /* Generate DMA buffer containing the commands.
    1388      * Store the command buffer descriptor pointer to pDmaBufferPrivateData.
    1389      */
    1390     GARENDERDATA *pRenderData = NULL;
    1391     uint32_t u32TargetLength = 0;
    1392     uint32_t cbPrivateData = 0;
    1393 
    1394     if (pBuildPagingBuffer->DmaBufferPrivateDataSize >= sizeof(GARENDERDATA))
    1395     {
    1396         // void *pvTarget          = pBuildPagingBuffer->pDmaBuffer;
    1397         const uint32_t cbTarget = pBuildPagingBuffer->DmaSize;
    1398         if (cbTarget > GA_DMA_MIN_SUBMIT_SIZE)
    1399         {
    1400             switch (pBuildPagingBuffer->Operation)
    1401             {
    1402                 case DXGK_OPERATION_TRANSFER:
    1403                 {
    1404                     GALOG(("DXGK_OPERATION_TRANSFER: %p: @0x%x, cb 0x%x; src: %d:%p; dst: %d:%p; flags 0x%x, off 0x%x\n",
    1405                            pBuildPagingBuffer->Transfer.hAllocation,
    1406                            pBuildPagingBuffer->Transfer.TransferOffset,
    1407                            pBuildPagingBuffer->Transfer.TransferSize,
    1408                            pBuildPagingBuffer->Transfer.Source.SegmentId,
    1409                            pBuildPagingBuffer->Transfer.Source.pMdl,
    1410                            pBuildPagingBuffer->Transfer.Destination.SegmentId,
    1411                            pBuildPagingBuffer->Transfer.Destination.pMdl,
    1412                            pBuildPagingBuffer->Transfer.Flags.Value,
    1413                            pBuildPagingBuffer->Transfer.MdlOffset));
    1414                     if (pBuildPagingBuffer->Transfer.Source.SegmentId == 0)
    1415                     {
    1416                         /* SysMem source. */
    1417                         if (pBuildPagingBuffer->Transfer.Destination.SegmentId == 1)
    1418                         {
    1419                             /* SysMem -> VRAM. */
    1420                             Status = gaSoftwarePagingTransfer(pDevExt, pBuildPagingBuffer);
    1421                             if (Status == STATUS_SUCCESS)
    1422                             {
    1423                                 /* Generate a NOP. */
    1424                                 Status = STATUS_NOT_SUPPORTED;
    1425                             }
    1426                         }
    1427                         else if (pBuildPagingBuffer->Transfer.Destination.SegmentId == 0)
    1428                         {
    1429                             /* SysMem -> SysMem, should not happen, bugcheck. */
    1430                             AssertFailed();
    1431                             Status = STATUS_INVALID_PARAMETER;
    1432                         }
    1433                         else
    1434                         {
    1435                             /* SysMem -> GPU surface. Our driver probably does not need it.
    1436                              * SVGA_3D_CMD_SURFACE_DMA(GMR -> Surface)?
    1437                              */
    1438                             AssertFailed();
    1439                             Status = STATUS_NOT_SUPPORTED;
    1440                         }
    1441                     }
    1442                     else if (pBuildPagingBuffer->Transfer.Source.SegmentId == 1)
    1443                     {
    1444                         /* VRAM source. */
    1445                         if (pBuildPagingBuffer->Transfer.Destination.SegmentId == 0)
    1446                         {
    1447                             /* VRAM -> SysMem. */
    1448                             Status = gaSoftwarePagingTransfer(pDevExt, pBuildPagingBuffer);
    1449                             if (Status == STATUS_SUCCESS)
    1450                             {
    1451                                 /* Generate a NOP. */
    1452                                 Status = STATUS_NOT_SUPPORTED;
    1453                             }
    1454                         }
    1455                         else if (pBuildPagingBuffer->Transfer.Destination.SegmentId == 1)
    1456                         {
    1457                             /* VRAM -> VRAM, should not happen, bugcheck. */
    1458                             AssertFailed();
    1459                             Status = STATUS_INVALID_PARAMETER;
    1460                         }
    1461                         else
    1462                         {
    1463                             /* VRAM -> GPU surface. Our driver probably does not need it.
    1464                              * SVGA_3D_CMD_SURFACE_DMA(SVGA_GMR_FRAMEBUFFER -> Surface)?
    1465                              */
    1466                             AssertFailed();
    1467                             Status = STATUS_NOT_SUPPORTED;
    1468                         }
    1469                     }
    1470                     else
    1471                     {
    1472                         /* GPU surface. Our driver probably does not need it.
    1473                          * SVGA_3D_CMD_SURFACE_DMA(Surface -> GMR)?
    1474                          */
    1475                         AssertFailed();
    1476                         Status = STATUS_NOT_SUPPORTED;
    1477                     }
    1478 
    1479                     /** @todo Ignore for now. */
    1480                     if (Status == STATUS_NOT_SUPPORTED)
    1481                     {
    1482                         /* NOP */
    1483                         Status = STATUS_SUCCESS;
    1484                     }
    1485                 } break;
    1486 
    1487                 case DXGK_OPERATION_FILL:
    1488                 {
    1489                     GALOG(("DXGK_OPERATION_FILL: %p: cb 0x%x, pattern 0x%x, %d:0x%08X\n",
    1490                            pBuildPagingBuffer->Fill.hAllocation,
    1491                            pBuildPagingBuffer->Fill.FillSize,
    1492                            pBuildPagingBuffer->Fill.FillPattern,
    1493                            pBuildPagingBuffer->Fill.Destination.SegmentId,
    1494                            pBuildPagingBuffer->Fill.Destination.SegmentAddress.LowPart));
    1495                     /* NOP */
    1496                 } break;
    1497 
    1498                 case DXGK_OPERATION_DISCARD_CONTENT:
    1499                 {
    1500                     GALOG(("DXGK_OPERATION_DISCARD_CONTENT: %p: flags 0x%x, %d:0x%08X\n",
    1501                            pBuildPagingBuffer->DiscardContent.hAllocation,
    1502                            pBuildPagingBuffer->DiscardContent.Flags,
    1503                            pBuildPagingBuffer->DiscardContent.SegmentId,
    1504                            pBuildPagingBuffer->DiscardContent.SegmentAddress.LowPart));
    1505                     /* NOP */
    1506                 } break;
    1507 
    1508                 default:
    1509                     AssertFailed();
    1510                     break;
    1511             }
    1512         }
    1513         else
    1514         {
    1515             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1516         }
    1517 
    1518         /* Fill RenderData description in any case, it will be ignored if the above code failed. */
    1519         pRenderData = (GARENDERDATA *)pBuildPagingBuffer->pDmaBufferPrivateData;
    1520         pRenderData->u32DataType  = GARENDERDATA_TYPE_PAGING;
    1521         pRenderData->cbData       = u32TargetLength;
    1522         pRenderData->pFenceObject = NULL; /* Not a user request, so no user accessible fence object. */
    1523         pRenderData->pvDmaBuffer = pBuildPagingBuffer->pDmaBuffer;
    1524         cbPrivateData = sizeof(GARENDERDATA);
    1525     }
    1526     else
    1527     {
    1528         Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1529     }
    1530 
    1531     switch (Status)
    1532     {
    1533         case STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER:
    1534             AssertFailed(); /** @todo test */
    1535             if (pRenderData == NULL)
    1536             {
    1537                 /* Not enough space in pDmaBufferPrivateData. */
    1538                 break;
    1539             }
    1540             RT_FALL_THRU();
    1541         case STATUS_SUCCESS:
    1542         {
    1543             if (u32TargetLength)
    1544             {
    1545                 pBuildPagingBuffer->pDmaBuffer = (uint8_t *)pBuildPagingBuffer->pDmaBuffer + u32TargetLength;
    1546                 pBuildPagingBuffer->pDmaBufferPrivateData = (uint8_t *)pBuildPagingBuffer->pDmaBufferPrivateData + cbPrivateData;
    1547             }
    1548         } break;
    1549         default: break;
    1550     }
    1551 
    1552     return STATUS_SUCCESS;
    1553 }
    1554 
    1555 NTSTATUS APIENTRY GaDxgkDdiPatch(const HANDLE hAdapter, const DXGKARG_PATCH *pPatch)
    1556 {
    1557     RT_NOREF2(hAdapter, pPatch);
    1558     /* Nothing to do. */
    1559 
    1560     uint8_t *pu8DMABuffer = (uint8_t *)pPatch->pDmaBuffer + pPatch->DmaBufferSubmissionStartOffset;
    1561     UINT const cbDMABuffer = pPatch->DmaBufferSubmissionEndOffset - pPatch->DmaBufferSubmissionStartOffset;
    1562 
    1563     UINT i;
    1564     for (i = pPatch->PatchLocationListSubmissionStart; i < pPatch->PatchLocationListSubmissionLength; ++i)
    1565     {
    1566         D3DDDI_PATCHLOCATIONLIST const *pPatchList = &pPatch->pPatchLocationList[i];
    1567         Assert(pPatchList->AllocationIndex < pPatch->AllocationListSize);
    1568 
    1569         DXGK_ALLOCATIONLIST const *pAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
    1570         if (pAllocationList->SegmentId == 0)
    1571         {
    1572             WARN(("no segment id specified"));
    1573             continue;
    1574         }
    1575 
    1576         Assert(pAllocationList->SegmentId == 1);            /* CPU visible segment. */
    1577         Assert(pAllocationList->PhysicalAddress.HighPart == 0); /* The segment is less than 4GB. */
    1578         Assert(!(pAllocationList->PhysicalAddress.QuadPart & 0xfffUL)); /* <- just a check to ensure allocation offset does not go here */
    1579 
    1580         if (pPatchList->PatchOffset == ~0UL)
    1581         {
    1582             /* This is a dummy patch request, ignore. */
    1583             continue;
    1584         }
    1585 
    1586         if (pPatchList->PatchOffset >= cbDMABuffer) /// @todo A better condition.
    1587         {
    1588             WARN(("pPatchList->PatchOffset(%d) >= cbDMABuffer(%d)", pPatchList->PatchOffset, cbDMABuffer));
    1589             return STATUS_INVALID_PARAMETER;
    1590         }
    1591 
    1592         uint32_t *poffVRAM = (uint32_t *)(pu8DMABuffer + pPatchList->PatchOffset);
    1593         *poffVRAM = pAllocationList->PhysicalAddress.LowPart + pPatchList->AllocationOffset;
    1594     }
    1595 
    1596     return STATUS_SUCCESS;
    1597 }
    1598 
    1599 NTSTATUS APIENTRY GaDxgkDdiSubmitCommand(const HANDLE hAdapter, const DXGKARG_SUBMITCOMMAND *pSubmitCommand)
    1600 {
    1601     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1602     PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pSubmitCommand->hContext;
    1603     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1604 
    1605     GALOG(("pContext %p, fence %d\n", pContext, pSubmitCommand->SubmissionFenceId));
    1606 
    1607     const uint32_t cbPrivateData = pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset - pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset;
    1608     void *pvPrivateData = (uint8_t *)pSubmitCommand->pDmaBufferPrivateData + pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset;
    1609 
    1610     GALOG(("DmaBuffer (fence %d): End %d, Start %d\n",
    1611            pSubmitCommand->SubmissionFenceId, pSubmitCommand->DmaBufferSubmissionEndOffset,
    1612            pSubmitCommand->DmaBufferSubmissionStartOffset));
    1613     GALOG(("PrivateData (fence %d): End %d, Start %d, cb %d\n",
    1614            pSubmitCommand->SubmissionFenceId, pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset,
    1615            pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset, cbPrivateData));
    1616 
    1617     uint32_t cbDmaBufferSubmission = pSubmitCommand->DmaBufferSubmissionEndOffset - pSubmitCommand->DmaBufferSubmissionStartOffset;
    1618     uint32_t cDataBlocks = cbPrivateData / sizeof(GARENDERDATA);
    1619     AssertReturn(cDataBlocks, STATUS_INVALID_PARAMETER);
    1620 
    1621     GARENDERDATA *pRenderData = (GARENDERDATA *)pvPrivateData;
    1622     while (cDataBlocks--)
    1623     {
    1624         AssertReturn(cbDmaBufferSubmission >= pRenderData->cbData, STATUS_INVALID_PARAMETER);
    1625         cbDmaBufferSubmission -= pRenderData->cbData;
    1626 
    1627         void *pvDmaBuffer = NULL;
    1628         if (   pRenderData->u32DataType == GARENDERDATA_TYPE_RENDER
    1629             || pRenderData->u32DataType == GARENDERDATA_TYPE_FENCE)
    1630         {
    1631             if (pRenderData->u32DataType == GARENDERDATA_TYPE_RENDER)
    1632             {
    1633                 pvDmaBuffer = pRenderData->pvDmaBuffer;
    1634                 AssertPtrReturn(pvDmaBuffer, STATUS_INVALID_PARAMETER);
    1635             }
    1636 
    1637             GAFENCEOBJECT * const pFO = pRenderData->pFenceObject;
    1638             if (pFO) /* Can be NULL if the user mode driver does not need the fence for this buffer. */
    1639             {
    1640                 GALOG(("pFO = %p, u32FenceHandle = %d, Fence = %d\n",
    1641                        pFO, pFO->u32FenceHandle, pSubmitCommand->SubmissionFenceId));
    1642 
    1643                 gaFenceObjectsLock(pGaDevExt);
    1644 
    1645                 Assert(pFO->u32FenceState == GAFENCE_STATE_IDLE);
    1646                 pFO->u32SubmissionFenceId = pSubmitCommand->SubmissionFenceId;
    1647                 pFO->u32FenceState = GAFENCE_STATE_SUBMITTED;
    1648                 pFO->u64SubmittedTS = RTTimeNanoTS();
    1649 
    1650                 gaFenceObjectsUnlock(pGaDevExt);
    1651             }
    1652         }
    1653         else if (pRenderData->u32DataType == GARENDERDATA_TYPE_PRESENT)
    1654         {
    1655             pvDmaBuffer = pRenderData->pvDmaBuffer;
    1656             AssertPtrReturn(pvDmaBuffer, STATUS_INVALID_PARAMETER);
    1657         }
    1658         else if (pRenderData->u32DataType == GARENDERDATA_TYPE_PAGING)
    1659         {
    1660             pvDmaBuffer = pRenderData->pvDmaBuffer;
    1661             AssertPtrReturn(pvDmaBuffer, STATUS_INVALID_PARAMETER);
    1662         }
    1663         else
    1664         {
    1665             AssertFailedReturn(STATUS_INVALID_PARAMETER);
    1666         }
    1667 
    1668         if (pvDmaBuffer)
    1669         {
    1670             /* Copy DmaBuffer to Fifo. */
    1671             Assert(pSubmitCommand->DmaBufferSegmentId == 0);
    1672 
    1673             uint32_t const cbSubmit = pRenderData->cbData;
    1674 
    1675             void *pvCmd = SvgaFifoReserve(pGaDevExt->hw.pSvga, cbSubmit);
    1676             AssertPtrReturn(pvCmd, STATUS_INSUFFICIENT_RESOURCES);
    1677 
    1678             /* pvDmaBuffer is the actual address of the current data block.
    1679              * Therefore do not use pSubmitCommand->DmaBufferSubmissionStartOffset here.
    1680              */
    1681             memcpy(pvCmd, pvDmaBuffer, cbSubmit);
    1682             SvgaFifoCommit(pGaDevExt->hw.pSvga, cbSubmit);
    1683         }
    1684 
    1685         ++pRenderData;
    1686     }
    1687 
    1688     /* Submit the fence. */
    1689     SvgaFence(pGaDevExt->hw.pSvga, pSubmitCommand->SubmissionFenceId);
    1690 
    1691     ASMAtomicWriteU32(&pGaDevExt->u32LastSubmittedFenceId, pSubmitCommand->SubmissionFenceId);
    1692 
    1693     GALOG(("done %d\n", pSubmitCommand->SubmissionFenceId));
    1694     return STATUS_SUCCESS;
    1695 }
    1696 
    1697 BOOLEAN GaDxgkDdiInterruptRoutine(const PVOID MiniportDeviceContext,
    1698                                   ULONG MessageNumber)
    1699 {
    1700     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
    1701     RT_NOREF(MessageNumber);
    1702 
    1703     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1704     if (!pGaDevExt)
    1705     {
    1706         /* Device is not initialized yet. Not a Gallium interrupt, "return FALSE immediately". */
    1707         return FALSE;
    1708     }
    1709 
    1710     PVBOXWDDM_EXT_VMSVGA pSvga = pGaDevExt->hw.pSvga;
    1711     if (!pSvga)
    1712     {
    1713         /* Device is not initialized yet. Not a VMSVGA interrupt, "return FALSE immediately". */
    1714         return FALSE;
    1715     }
    1716 
    1717     const uint32_t u32IrqStatus = SVGAPortRead(pSvga, SVGA_IRQSTATUS_PORT);
    1718     if (!u32IrqStatus)
    1719     {
    1720         /* Not a VMSVGA interrupt, "return FALSE immediately". */
    1721         return FALSE;
    1722     }
    1723 
    1724     /* "Dismiss the interrupt on the adapter." */
    1725     SVGAPortWrite(pSvga, SVGA_IRQSTATUS_PORT, u32IrqStatus);
    1726     GALOG(("u32IrqStatus = 0x%08X\n", u32IrqStatus));
    1727 
    1728     /* Check what happened. */
    1729     if (u32IrqStatus & SVGA_IRQFLAG_ANY_FENCE)
    1730     {
    1731         /* A SVGA_CMD_FENCE command has been processed by the device. */
    1732         gaReportFence(pDevExt);
    1733     }
    1734 
    1735     GALOG(("leave\n"));
    1736     /* "Return TRUE as quickly as possible". */
    1737     return TRUE;
    1738 }
    1739 
    1740 VOID GaDxgkDdiDpcRoutine(const PVOID MiniportDeviceContext)
    1741 {
    1742     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
    1743     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1744     if (!pGaDevExt)
    1745     {
    1746         /* Device is not initialized yet. */
    1747         return;
    1748     }
    1749 
    1750     // pDevExt->u.primary.DxgkInterface.DxgkCbNotifyDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
    1751 
    1752     /* Scan fence objects and mark all with u32FenceId < u32LastCompletedFenceId as SIGNALED */
    1753     const uint32_t u32LastCompletedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedFenceId);
    1754 
    1755     gaFenceObjectsLock(pGaDevExt);
    1756 
    1757     GAFENCEOBJECT *pIter, *pNext;
    1758     RTListForEachSafe(&pGaDevExt->fenceObjects.list, pIter, pNext, GAFENCEOBJECT, node)
    1759     {
    1760         if (pIter->u32FenceState == GAFENCE_STATE_SUBMITTED)
    1761         {
    1762             if (gaFenceCmp(pIter->u32SubmissionFenceId, u32LastCompletedFenceId) <= 0)
    1763             {
    1764                 GALOG(("u32SubmissionFenceId %u -> SIGNALED %RU64 ns\n",
    1765                        pIter->u32SubmissionFenceId, RTTimeNanoTS() - pIter->u64SubmittedTS));
    1766 
    1767                 ASMAtomicWriteU32(&pGaDevExt->u32LastCompletedSeqNo, pIter->u32SeqNo);
    1768                 pIter->u32FenceState = GAFENCE_STATE_SIGNALED;
    1769                 if (RT_BOOL(pIter->fu32FenceFlags & GAFENCE_F_WAITED))
    1770                 {
    1771                     KeSetEvent(&pIter->event, 0, FALSE);
    1772                 }
    1773 
    1774                 gaFenceUnrefLocked(pGaDevExt, pIter);
    1775             }
    1776         }
    1777     }
    1778 
    1779     gaFenceObjectsUnlock(pGaDevExt);
    1780 }
    1781 
    1782 typedef struct GAPREEMPTCOMMANDCBCTX
    1783 {
    1784     PVBOXMP_DEVEXT pDevExt;
    1785     UINT uPreemptionFenceId;
    1786     UINT uLastCompletedFenceId;
    1787 } GAPREEMPTCOMMANDCBCTX;
    1788 
    1789 static BOOLEAN gaPreemptCommandCb(PVOID Context)
    1790 {
    1791     GAPREEMPTCOMMANDCBCTX *pCtx = (GAPREEMPTCOMMANDCBCTX *)Context;
    1792     dxgkNotifyDma(&pCtx->pDevExt->u.primary.DxgkInterface, DXGK_INTERRUPT_DMA_PREEMPTED,
    1793                   0, pCtx->uPreemptionFenceId, pCtx->uLastCompletedFenceId);
    1794     return TRUE;
    1795 }
    1796 
    1797 NTSTATUS APIENTRY GaDxgkDdiPreemptCommand(const HANDLE hAdapter,
    1798                                           const DXGKARG_PREEMPTCOMMAND *pPreemptCommand)
    1799 {
    1800     NTSTATUS Status;
    1801 
    1802     GALOG(("hAdapter %p, fence %d\n", hAdapter, pPreemptCommand->PreemptionFenceId));
    1803 
    1804     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1805     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1806     if (!pGaDevExt)
    1807     {
    1808         /* Device is not initialized yet. */
    1809         return STATUS_SUCCESS;
    1810     }
    1811 
    1812     /* We can not safely remove submitted data from FIFO, so just let the host process all submitted commands.
    1813      */
    1814     const uint32_t u32LastCompletedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedFenceId);
    1815     const uint32_t u32LastSubmittedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastSubmittedFenceId);
    1816     if (u32LastCompletedFenceId == u32LastSubmittedFenceId)
    1817     {
    1818         GAPREEMPTCOMMANDCBCTX Ctx;
    1819         Ctx.pDevExt = pDevExt;
    1820         Ctx.uPreemptionFenceId = pPreemptCommand->PreemptionFenceId;
    1821         Ctx.uLastCompletedFenceId = u32LastCompletedFenceId;
    1822 
    1823         DXGKRNL_INTERFACE *pDxgkInterface = &pDevExt->u.primary.DxgkInterface;
    1824         BOOLEAN bReturnValue = FALSE;
    1825         Status = pDxgkInterface->DxgkCbSynchronizeExecution(pDxgkInterface->DeviceHandle,
    1826                                                             gaPreemptCommandCb, &Ctx, 0, &bReturnValue);
    1827         Assert(bReturnValue);
    1828     }
    1829     else
    1830     {
    1831         /* Submit the fence. */
    1832         Assert(pGaDevExt->u32PreemptionFenceId == 0);
    1833         ASMAtomicWriteU32(&pGaDevExt->u32PreemptionFenceId, pPreemptCommand->PreemptionFenceId);
    1834         Status = SvgaFence(pGaDevExt->hw.pSvga, pPreemptCommand->PreemptionFenceId);
    1835     }
    1836 
    1837     return Status;
    1838 }
    1839 
    1840 static BOOLEAN gaQueryCurrentFenceCb(PVOID Context)
    1841 {
    1842     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)Context;
    1843     gaReportFence(pDevExt);
    1844     return TRUE;
    1845 }
    1846 
    1847 NTSTATUS APIENTRY GaDxgkDdiQueryCurrentFence(const HANDLE hAdapter,
    1848                                              DXGKARG_QUERYCURRENTFENCE *pCurrentFence)
    1849 {
    1850     NTSTATUS Status;
    1851 
    1852     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1853     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1854     if (!pGaDevExt)
    1855     {
    1856         /* Device is not initialized yet. */
    1857         return STATUS_SUCCESS;
    1858     }
    1859 
    1860     DXGKRNL_INTERFACE *pDxgkInterface = &pDevExt->u.primary.DxgkInterface;
    1861     LARGE_INTEGER DelayInterval;
    1862     DelayInterval.QuadPart = -10LL * 1000LL * 1000LL;
    1863     uint32_t u32LastCompletedFenceId = 0;
    1864 
    1865     /* Wait until the host processes all submitted buffers to allow delays on the host (debug, etc). */
    1866     for (;;)
    1867     {
    1868         BOOLEAN bReturnValue = FALSE;
    1869         Status = pDxgkInterface->DxgkCbSynchronizeExecution(pDxgkInterface->DeviceHandle,
    1870                                                             gaQueryCurrentFenceCb, pDevExt, 0, &bReturnValue);
    1871         Assert(bReturnValue);
    1872         if (Status != STATUS_SUCCESS)
    1873         {
    1874             break;
    1875         }
    1876 
    1877         u32LastCompletedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedFenceId);
    1878         uint32_t const u32LastSubmittedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastSubmittedFenceId);
    1879         if (u32LastCompletedFenceId == u32LastSubmittedFenceId)
    1880         {
    1881             break;
    1882         }
    1883 
    1884         GALOG(("hAdapter %p, LastCompletedFenceId %d, LastSubmittedFenceId %d...\n", hAdapter, u32LastCompletedFenceId, u32LastSubmittedFenceId));
    1885 
    1886         KeDelayExecutionThread(KernelMode, FALSE, &DelayInterval);
    1887     }
    1888 
    1889     if (Status == STATUS_SUCCESS)
    1890     {
    1891         pCurrentFence->CurrentFence = u32LastCompletedFenceId;
    1892     }
    1893 
    1894     GALOG(("hAdapter %p, CurrentFence %d, Status 0x%x\n", hAdapter, pCurrentFence->CurrentFence, Status));
    1895 
    1896     return Status;
    1897 }
    1898 
    1899 NTSTATUS APIENTRY GaDxgkDdiEscape(const HANDLE hAdapter,
    1900                                   const DXGKARG_ESCAPE *pEscape)
    1901 {
    1902     if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE))
    1903     {
    1904         AssertFailed();
    1905         return STATUS_INVALID_PARAMETER;
    1906     }
    1907 
    1908     NTSTATUS Status = STATUS_NOT_SUPPORTED;
    1909     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1910     PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)pEscape->hDevice;
    1911     PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
    1912     const VBOXDISPIFESCAPE *pEscapeHdr = (VBOXDISPIFESCAPE *)pEscape->pPrivateDriverData;
    1913     switch (pEscapeHdr->escapeCode)
    1914     {
    1915         case VBOXESC_GAGETCID:
    1916         {
    1917             if (!pContext)
    1918             {
    1919                 Status = STATUS_INVALID_PARAMETER;
    1920                 break;
    1921             }
    1922 
    1923             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAGETCID))
    1924             {
    1925                 Status = STATUS_INVALID_PARAMETER;
    1926                 break;
    1927             }
    1928 
    1929             VBOXDISPIFESCAPE_GAGETCID *pGaGetCid = (VBOXDISPIFESCAPE_GAGETCID *)pEscapeHdr;
    1930             pGaGetCid->u32Cid = pContext->u32Cid;
    1931             Status = STATUS_SUCCESS;
    1932             break;
    1933         }
    1934         case VBOXESC_GAREGION:
    1935         {
    1936             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAREGION))
    1937             {
    1938                 Status = STATUS_INVALID_PARAMETER;
    1939                 break;
    1940             }
    1941 
    1942             VBOXDISPIFESCAPE_GAREGION *pGaRegion = (VBOXDISPIFESCAPE_GAREGION *)pEscapeHdr;
    1943             if (pGaRegion->u32Command == GA_REGION_CMD_CREATE)
    1944             {
    1945                 Status = SvgaRegionCreate(pDevExt->pGa->hw.pSvga, pDevice, pGaRegion->u32NumPages, &pGaRegion->u32GmrId, &pGaRegion->u64UserAddress);
    1946             }
    1947             else if (pGaRegion->u32Command == GA_REGION_CMD_DESTROY)
    1948             {
    1949                 Status = SvgaRegionDestroy(pDevExt->pGa->hw.pSvga, pGaRegion->u32GmrId);
    1950             }
    1951             else
    1952             {
    1953                 Status = STATUS_INVALID_PARAMETER;
    1954             }
    1955         } break;
    1956         case VBOXESC_GAPRESENT:
    1957         {
    1958             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAPRESENT))
    1959             {
    1960                 Status = STATUS_INVALID_PARAMETER;
    1961                 break;
    1962             }
    1963 
    1964             VBOXDISPIFESCAPE_GAPRESENT *pGaPresent = (VBOXDISPIFESCAPE_GAPRESENT *)pEscapeHdr;
    1965             /** @todo This always writes to the start of VRAM. This is a debug function
    1966              * and is not used for normal operations anymore.
    1967              */
    1968             Status = gaPresent(pDevExt->pGa, pGaPresent->u32Sid, pGaPresent->u32Width, pGaPresent->u32Height, 0);
    1969             break;
    1970         }
    1971         case VBOXESC_GASURFACEDEFINE:
    1972         {
    1973             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GASURFACEDEFINE))
    1974             {
    1975                 Status = STATUS_INVALID_PARAMETER;
    1976                 break;
    1977             }
    1978 
    1979             VBOXDISPIFESCAPE_GASURFACEDEFINE *pGaSurfaceDefine = (VBOXDISPIFESCAPE_GASURFACEDEFINE *)pEscapeHdr;
    1980             if (pEscape->PrivateDriverDataSize - sizeof(VBOXDISPIFESCAPE_GASURFACEDEFINE) < pGaSurfaceDefine->cbReq)
    1981             {
    1982                 Status = STATUS_INVALID_PARAMETER;
    1983                 break;
    1984             }
    1985 
    1986             GASURFCREATE *pCreateParms = (GASURFCREATE *)&pGaSurfaceDefine[1];
    1987             GASURFSIZE *paSizes = (GASURFSIZE *)&pCreateParms[1];
    1988 
    1989             /// @todo verify the data
    1990             Status = gaSurfaceDefine(pDevExt->pGa, pCreateParms, paSizes, pGaSurfaceDefine->cSizes, &pGaSurfaceDefine->u32Sid);
    1991             break;
    1992         }
    1993         case VBOXESC_GASURFACEDESTROY:
    1994         {
    1995             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GASURFACEDESTROY))
    1996             {
    1997                 Status = STATUS_INVALID_PARAMETER;
    1998                 break;
    1999             }
    2000 
    2001             VBOXDISPIFESCAPE_GASURFACEDESTROY *pGaSurfaceDestroy = (VBOXDISPIFESCAPE_GASURFACEDESTROY *)pEscapeHdr;
    2002             Status = gaSurfaceDestroy(pDevExt->pGa, pGaSurfaceDestroy->u32Sid);
    2003             break;
    2004         }
    2005         case VBOXESC_GASHAREDSID:
    2006         {
    2007             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GASHAREDSID))
    2008             {
    2009                 Status = STATUS_INVALID_PARAMETER;
    2010                 break;
    2011             }
    2012 
    2013             VBOXDISPIFESCAPE_GASHAREDSID *pGaSharedSid = (VBOXDISPIFESCAPE_GASHAREDSID *)pEscapeHdr;
    2014             if (pGaSharedSid->u32SharedSid == ~0)
    2015             {
    2016                 Status = gaSharedSidRemove(pDevExt->pGa, pGaSharedSid->u32Sid);
    2017             }
    2018             else
    2019             {
    2020                 Status = gaSharedSidInsert(pDevExt->pGa, pGaSharedSid->u32Sid, pGaSharedSid->u32SharedSid);
    2021             }
    2022             break;
    2023         }
    2024         case VBOXESC_GAFENCECREATE:
    2025         {
    2026             if (!pDevice)
    2027             {
    2028                 Status = STATUS_INVALID_PARAMETER;
    2029                 break;
    2030             }
    2031 
    2032             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAFENCECREATE))
    2033             {
    2034                 Status = STATUS_INVALID_PARAMETER;
    2035                 break;
    2036             }
    2037 
    2038             VBOXDISPIFESCAPE_GAFENCECREATE *pFenceCreate = (VBOXDISPIFESCAPE_GAFENCECREATE *)pEscapeHdr;
    2039             Status = GaFenceCreate(pDevExt->pGa, pDevice, &pFenceCreate->u32FenceHandle);
    2040             break;
    2041         }
    2042         case VBOXESC_GAFENCEQUERY:
    2043         {
    2044             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAFENCEQUERY))
    2045             {
    2046                 Status = STATUS_INVALID_PARAMETER;
    2047                 break;
    2048             }
    2049 
    2050             VBOXDISPIFESCAPE_GAFENCEQUERY *pFenceQuery = (VBOXDISPIFESCAPE_GAFENCEQUERY *)pEscapeHdr;
    2051             Status = GaFenceQuery(pDevExt->pGa, pFenceQuery->u32FenceHandle,
    2052                                   &pFenceQuery->u32SubmittedSeqNo, &pFenceQuery->u32ProcessedSeqNo,
    2053                                   &pFenceQuery->u32FenceStatus);
    2054             break;
    2055         }
    2056         case VBOXESC_GAFENCEWAIT:
    2057         {
    2058             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAFENCEWAIT))
    2059             {
    2060                 Status = STATUS_INVALID_PARAMETER;
    2061                 break;
    2062             }
    2063 
    2064             VBOXDISPIFESCAPE_GAFENCEWAIT *pFenceWait = (VBOXDISPIFESCAPE_GAFENCEWAIT *)pEscapeHdr;
    2065             Status = GaFenceWait(pDevExt->pGa, pFenceWait->u32FenceHandle, pFenceWait->u32TimeoutUS);
    2066             break;
    2067         }
    2068         case VBOXESC_GAFENCEUNREF:
    2069         {
    2070             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAFENCEUNREF))
    2071             {
    2072                 Status = STATUS_INVALID_PARAMETER;
    2073                 break;
    2074             }
    2075 
    2076             VBOXDISPIFESCAPE_GAFENCEUNREF *pFenceUnref = (VBOXDISPIFESCAPE_GAFENCEUNREF *)pEscapeHdr;
    2077             Status = GaFenceUnref(pDevExt->pGa, pFenceUnref->u32FenceHandle);
    2078             break;
    2079         }
    2080         default:
    2081             break;
    2082     }
    2083 
    2084     return Status;
    2085 }
    2086 
    2087 DECLINLINE(VBOXVIDEOOFFSET) vboxWddmAddrVRAMOffset(VBOXWDDM_ADDR const *pAddr)
    2088 {
    2089     return (pAddr->offVram != VBOXVIDEOOFFSET_VOID && pAddr->SegmentId) ?
    2090                 (pAddr->SegmentId == 1 ? pAddr->offVram : 0) :
    2091                 VBOXVIDEOOFFSET_VOID;
    2092 }
    2093 
    2094 static void vboxWddmRectCopy(void *pvDst, uint32_t cbDstBytesPerPixel, uint32_t cbDstPitch,
    2095                              void const *pvSrc, uint32_t cbSrcBytesPerPixel, uint32_t cbSrcPitch,
    2096                              RECT const *pRect)
    2097 {
    2098     uint8_t *pu8Dst = (uint8_t *)pvDst;
    2099     pu8Dst += pRect->top * cbDstPitch + pRect->left * cbDstBytesPerPixel;
    2100 
    2101     uint8_t const *pu8Src = (uint8_t *)pvSrc;
    2102     pu8Src += pRect->top * cbSrcPitch + pRect->left * cbSrcBytesPerPixel;
    2103 
    2104     uint32_t const cbLine = (pRect->right - pRect->left) * cbDstBytesPerPixel;
    2105     for (INT y = pRect->top; y < pRect->bottom; ++y)
    2106     {
    2107         memcpy(pu8Dst, pu8Src, cbLine);
    2108         pu8Dst += cbDstPitch;
    2109         pu8Src += cbSrcPitch;
    2110     }
    2111 }
    2112 
    2113 static NTSTATUS gaSourceBlitToScreen(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_SOURCE *pSource, RECT const *pRect)
    2114 {
    2115     NTSTATUS Status = STATUS_SUCCESS;
    2116     PVBOXWDDM_EXT_VMSVGA pSvga = pDevExt->pGa->hw.pSvga;
    2117 
    2118     VBOXWDDM_TARGET_ITER Iter;
    2119     VBoxVidPnStTIterInit(pSource, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, &Iter);
    2120     for (PVBOXWDDM_TARGET pTarget = VBoxVidPnStTIterNext(&Iter);
    2121          pTarget;
    2122          pTarget = VBoxVidPnStTIterNext(&Iter))
    2123     {
    2124         Status = SvgaBlitGMRFBToScreen(pSvga,
    2125                                        pTarget->u32Id,
    2126                                        pRect->left,
    2127                                        pRect->top,
    2128                                        pRect);
    2129         AssertBreak(Status == STATUS_SUCCESS);
    2130     }
    2131 
    2132     return Status;
    2133 }
    2134 
    2135 NTSTATUS APIENTRY GaDxgkDdiPresentDisplayOnly(const HANDLE hAdapter,
    2136                                               const DXGKARG_PRESENT_DISPLAYONLY *pPresentDisplayOnly)
    2137 {
    2138     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    2139 
    2140     LOG(("VidPnSourceId %d, pSource %p, BytesPerPixel %d, Pitch %d, Flags 0x%x, NumMoves %d, NumDirtyRects %d, pfn %p\n",
    2141          pPresentDisplayOnly->VidPnSourceId,
    2142          pPresentDisplayOnly->pSource,
    2143          pPresentDisplayOnly->BytesPerPixel,
    2144          pPresentDisplayOnly->Pitch,
    2145          pPresentDisplayOnly->Flags.Value,
    2146          pPresentDisplayOnly->NumMoves,
    2147          pPresentDisplayOnly->NumDirtyRects,
    2148          pPresentDisplayOnly->pDirtyRect,
    2149          pPresentDisplayOnly->pfnPresentDisplayOnlyProgress));
    2150 
    2151     /*
    2152      * Copy the image to the corresponding VidPn source allocation.
    2153      */
    2154     PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pPresentDisplayOnly->VidPnSourceId];
    2155     AssertReturn(pSource->AllocData.Addr.SegmentId == 1, STATUS_SUCCESS); /* Ignore such VidPn sources. */
    2156 
    2157     VBOXVIDEOOFFSET const offVRAM = vboxWddmAddrVRAMOffset(&pSource->AllocData.Addr);
    2158     AssertReturn(offVRAM != VBOXVIDEOOFFSET_VOID, STATUS_SUCCESS); /* Ignore such VidPn sources. */
    2159 
    2160     for (ULONG i = 0; i < pPresentDisplayOnly->NumMoves; ++i)
    2161     {
    2162         RECT *pRect = &pPresentDisplayOnly->pMoves[i].DestRect;
    2163         vboxWddmRectCopy(pDevExt->pvVisibleVram + offVRAM,    // dst pointer
    2164                          pSource->AllocData.SurfDesc.bpp / 8, // dst bytes per pixel
    2165                          pSource->AllocData.SurfDesc.pitch,   // dst pitch
    2166                          pPresentDisplayOnly->pSource,        // src pointer
    2167                          pPresentDisplayOnly->BytesPerPixel,  // src bytes per pixel
    2168                          pPresentDisplayOnly->Pitch,          // src pitch
    2169                          pRect);
    2170     }
    2171 
    2172     for (ULONG i = 0; i < pPresentDisplayOnly->NumDirtyRects; ++i)
    2173     {
    2174         RECT *pRect = &pPresentDisplayOnly->pDirtyRect[i];
    2175         if (pRect->left >= pRect->right || pRect->top >= pRect->bottom)
    2176         {
    2177             continue;
    2178         }
    2179 
    2180         vboxWddmRectCopy(pDevExt->pvVisibleVram + offVRAM,    // dst pointer
    2181                          pSource->AllocData.SurfDesc.bpp / 8, // dst bytes per pixel
    2182                          pSource->AllocData.SurfDesc.pitch,   // dst pitch
    2183                          pPresentDisplayOnly->pSource,        // src pointer
    2184                          pPresentDisplayOnly->BytesPerPixel,  // src bytes per pixel
    2185                          pPresentDisplayOnly->Pitch,          // src pitch
    2186                          pRect);
    2187     }
    2188 
    2189     NTSTATUS Status = STATUS_SUCCESS;
    2190     if (pSource->bVisible) /// @todo Does/should this have any effect?
    2191     {
    2192         PVBOXWDDM_EXT_VMSVGA pSvga = pDevExt->pGa->hw.pSvga;
    2193         Status = SvgaDefineGMRFB(pSvga, (uint32_t)offVRAM, pSource->AllocData.SurfDesc.pitch, false);
    2194         if (Status == STATUS_SUCCESS)
    2195         {
    2196             for (ULONG i = 0; i < pPresentDisplayOnly->NumMoves; ++i)
    2197             {
    2198                 RECT *pRect = &pPresentDisplayOnly->pMoves[i].DestRect;
    2199                 Status = gaSourceBlitToScreen(pDevExt, pSource, pRect);
    2200                 AssertBreak(Status == STATUS_SUCCESS);
    2201             }
    2202         }
    2203 
    2204         if (Status == STATUS_SUCCESS)
    2205         {
    2206             for (ULONG i = 0; i < pPresentDisplayOnly->NumDirtyRects; ++i)
    2207             {
    2208                 RECT *pRect = &pPresentDisplayOnly->pDirtyRect[i];
    2209                 Status = gaSourceBlitToScreen(pDevExt, pSource, pRect);
    2210                 AssertBreak(Status == STATUS_SUCCESS);
    2211             }
    2212         }
    2213     }
    2214 
    2215     return Status;
    2216 }
    2217 
    2218 NTSTATUS GaVidPnSourceReport(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_SOURCE *pSource)
    2219 {
    2220     NTSTATUS Status = STATUS_SUCCESS;
    2221 
    2222     VBOXVIDEOOFFSET offVRAM = vboxWddmAddrVRAMOffset(&pSource->AllocData.Addr);
    2223     if (offVRAM == VBOXVIDEOOFFSET_VOID)
    2224         return STATUS_SUCCESS; /* Ignore such VidPn sources. */
    2225 
    2226     VBOXWDDM_TARGET_ITER Iter;
    2227     VBoxVidPnStTIterInit(pSource, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, &Iter);
    2228     for (PVBOXWDDM_TARGET pTarget = VBoxVidPnStTIterNext(&Iter);
    2229          pTarget;
    2230          pTarget = VBoxVidPnStTIterNext(&Iter))
    2231     {
    2232         Status = GaScreenDefine(pDevExt->pGa,
    2233                                 (uint32_t)offVRAM,
    2234                                 pTarget->u32Id,
    2235                                 pSource->VScreenPos.x, pSource->VScreenPos.y,
    2236                                 pSource->AllocData.SurfDesc.width, pSource->AllocData.SurfDesc.height,
    2237                                 RT_BOOL(pSource->bBlankedByPowerOff));
    2238         AssertBreak(Status == STATUS_SUCCESS);
    2239     }
    2240 
    2241     return Status;
    2242 }
    2243 
    2244 NTSTATUS GaVidPnSourceCheckPos(PVBOXMP_DEVEXT pDevExt, UINT iSource)
    2245 {
    2246     POINT Pos = {0};
    2247     NTSTATUS Status = vboxWddmDisplaySettingsQueryPos(pDevExt, iSource, &Pos);
    2248     if (NT_SUCCESS(Status))
    2249     {
    2250         PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[iSource];
    2251         if (memcmp(&pSource->VScreenPos, &Pos, sizeof(Pos)))
    2252         {
    2253             pSource->VScreenPos = Pos;
    2254             Status = GaVidPnSourceReport(pDevExt, pSource);
    2255         }
    2256     }
    2257     return Status;
    2258 }
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPGaUtils.cpp

    r76845 r76884  
    1616 */
    1717
    18 #include "VBoxMPGaWddm.h"
    19 #include "../VBoxMPVidPn.h"
     18#include "VBoxMPGaUtils.h"
    2019
    21 #include "Svga.h"
    22 #include "SvgaFifo.h"
    23 #include "SvgaCmd.h"
    24 #include "SvgaHw.h"
    25 
    26 #include <iprt/time.h>
     20#include <iprt/asm.h>
     21#include <iprt/assert.h>
    2722
    2823volatile uint32_t g_fu32GaLogControl =
     
    3328#endif
    3429;
    35 
    36 
    37 #define VBOXWDDM_GA_MAX_FENCE_OBJECTS 4096
    38 
    39 /* Gallium related device extension. */
    40 typedef struct VBOXWDDM_EXT_GA
    41 {
    42     union
    43     {
    44         /* Pointers to HW specific structs. */
    45         PVBOXWDDM_EXT_VMSVGA pSvga;
    46         void *pv;
    47     } hw;
    48 
    49     volatile uint32_t u32LastSubmittedFenceId; /* Updated in GaDxgkSubmitCommand. */
    50     volatile uint32_t u32LastCompletedFenceId; /* Updated in ISR. */
    51     volatile uint32_t u32PreemptionFenceId; /* Updated in GaDxgkDdiPreemptCommand. */
    52     volatile uint32_t u32LastCompletedSeqNo; /* Updated in DPC routine. */
    53 
    54     struct
    55     {
    56         /* Generation of SeqNo's. */
    57         volatile uint32_t u32SeqNoSource;
    58         /* Lock for accessing fence objects. Spin lock because it is used in DPC routine too. */
    59         KIRQL OldIrql;
    60         KSPIN_LOCK SpinLock;
    61         /* List of all fence objects. */
    62         RTLISTANCHOR list;
    63         /** Bitmap of used fence handles. Bit 0 - fence handle 0, etc. */
    64         uint32_t au32HandleBits[(VBOXWDDM_GA_MAX_FENCE_OBJECTS + 31) / 32];
    65     } fenceObjects;
    66 } VBOXWDDM_EXT_GA;
    67 
    68 /* Fence object (FO). */
    69 typedef struct GAFENCEOBJECT
    70 {
    71     volatile uint32_t cRefs;    /* By UM driver, by waiter, during submission. */
    72     uint32_t u32FenceHandle;    /* Unique identifier, used for communications with UM driver. */
    73     uint32_t u32FenceState;     /* GAFENCE_STATE_* */
    74     uint32_t fu32FenceFlags;    /* GAFENCE_F_* */
    75     uint32_t u32SubmissionFenceId; /* DXGK fence id. */
    76     uint32_t u32SeqNo;          /* Gallium Sequence Number, generated by the miniport. */
    77     PVBOXWDDM_DEVICE pDevice;   /* Device the fence is associated with. */
    78     KEVENT event;               /* Allows to wait for the fence completion. */
    79     RTLISTNODE node;            /* For the per adapter list of fence objects. */
    80     uint64_t u64SubmittedTS;    /* Nanoseconds timestamp when the corresponding buffer was submitted. */
    81 } GAFENCEOBJECT;
    82 
    83 #define GAFENCE_STATE_IDLE      0
    84 #define GAFENCE_STATE_SUBMITTED 1
    85 #define GAFENCE_STATE_SIGNALED  2
    86 
    87 #define GAFENCE_F_WAITED        0x1 /* KEVENT is initialized and there is(are) waiter(s). */
    88 
    8930
    9031/*
     
    14081    return STATUS_SUCCESS;
    14182}
    142 
    143 
    144 DECLINLINE(void) gaFenceObjectsLock(VBOXWDDM_EXT_GA *pGaDevExt)
    145 {
    146     KeAcquireSpinLock(&pGaDevExt->fenceObjects.SpinLock, &pGaDevExt->fenceObjects.OldIrql);
    147 }
    148 
    149 DECLINLINE(void) gaFenceObjectsUnlock(VBOXWDDM_EXT_GA *pGaDevExt)
    150 {
    151     KeReleaseSpinLock(&pGaDevExt->fenceObjects.SpinLock, pGaDevExt->fenceObjects.OldIrql);
    152 }
    153 
    154 static void gaFenceObjectsDestroy(VBOXWDDM_EXT_GA *pGaDevExt,
    155                                   PVBOXWDDM_DEVICE pDevice)
    156 {
    157     RTLISTANCHOR list;
    158     RTListInit(&list);
    159 
    160     gaFenceObjectsLock(pGaDevExt);
    161 
    162     GAFENCEOBJECT *pIter, *pNext;
    163     RTListForEachSafe(&pGaDevExt->fenceObjects.list, pIter, pNext, GAFENCEOBJECT, node)
    164     {
    165         if (   pDevice == NULL
    166             || pIter->pDevice == pDevice)
    167         {
    168             /* Remove from list, add to the local list. */
    169             RTListNodeRemove(&pIter->node);
    170             GaIdFree(pGaDevExt->fenceObjects.au32HandleBits, sizeof(pGaDevExt->fenceObjects.au32HandleBits),
    171                      VBOXWDDM_GA_MAX_FENCE_OBJECTS, pIter->u32FenceHandle);
    172             RTListAppend(&list, &pIter->node);
    173         }
    174     }
    175 
    176     gaFenceObjectsUnlock(pGaDevExt);
    177 
    178     /* Deallocate list. */
    179     RTListForEachSafe(&list, pIter, pNext, GAFENCEOBJECT, node)
    180     {
    181         GALOG(("Deallocate u32FenceHandle = %d for %p\n", pIter->u32FenceHandle, pDevice));
    182         RTListNodeRemove(&pIter->node);
    183         GaMemFree(pIter);
    184     }
    185 }
    186 
    187 static void gaFenceDelete(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
    188 {
    189     GALOG(("u32FenceHandle = %d, pFO %p\n", pFO->u32FenceHandle, pFO));
    190 
    191     gaFenceObjectsLock(pGaDevExt);
    192 
    193     RTListNodeRemove(&pFO->node);
    194     GaIdFree(pGaDevExt->fenceObjects.au32HandleBits, sizeof(pGaDevExt->fenceObjects.au32HandleBits),
    195              VBOXWDDM_GA_MAX_FENCE_OBJECTS, pFO->u32FenceHandle);
    196 
    197     gaFenceObjectsUnlock(pGaDevExt);
    198 
    199     /// @todo Pool of fence objects to avoid memory allocations.
    200     GaMemFree(pFO);
    201 }
    202 
    203 static void gaFenceDeleteLocked(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
    204 {
    205     GALOG(("u32FenceHandle = %d, pFO %p\n", pFO->u32FenceHandle, pFO));
    206 
    207     RTListNodeRemove(&pFO->node);
    208     GaIdFree(pGaDevExt->fenceObjects.au32HandleBits, sizeof(pGaDevExt->fenceObjects.au32HandleBits),
    209              VBOXWDDM_GA_MAX_FENCE_OBJECTS, pFO->u32FenceHandle);
    210 
    211     /// @todo Pool of fence objects to avoid memory allocations.
    212     GaMemFree(pFO);
    213 }
    214 
    215 DECLINLINE(void) gaFenceRef(GAFENCEOBJECT *pFO)
    216 {
    217     ASMAtomicIncU32(&pFO->cRefs);
    218 }
    219 
    220 DECLINLINE(void) gaFenceUnref(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
    221 {
    222     uint32_t c = ASMAtomicDecU32(&pFO->cRefs);
    223     Assert(c < UINT32_MAX / 2);
    224     if (c == 0)
    225     {
    226         gaFenceDelete(pGaDevExt, pFO);
    227     }
    228 }
    229 
    230 DECLINLINE(void) gaFenceUnrefLocked(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
    231 {
    232     uint32_t c = ASMAtomicDecU32(&pFO->cRefs);
    233     Assert(c < UINT32_MAX / 2);
    234     if (c == 0)
    235     {
    236         gaFenceDeleteLocked(pGaDevExt, pFO);
    237     }
    238 }
    239 
    240 static GAFENCEOBJECT *gaFenceLookup(VBOXWDDM_EXT_GA *pGaDevExt,
    241                                     uint32_t u32FenceHandle)
    242 {
    243     /* Must be called under the fence object lock. */
    244     GAFENCEOBJECT *pIter;
    245     RTListForEach(&pGaDevExt->fenceObjects.list, pIter, GAFENCEOBJECT, node)
    246     {
    247         if (pIter->u32FenceHandle == u32FenceHandle)
    248         {
    249             gaFenceRef(pIter);
    250             return pIter;
    251         }
    252     }
    253     return NULL;
    254 }
    255 
    256 
    257 void GaAdapterStop(PVBOXMP_DEVEXT pDevExt)
    258 {
    259     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    260     GALOG(("pDevExt = %p, pDevExt->pGa = %p\n", pDevExt, pGaDevExt));
    261 
    262     if (pGaDevExt)
    263     {
    264         /* Free fence objects. */
    265         gaFenceObjectsDestroy(pGaDevExt, NULL);
    266 
    267         if (pGaDevExt->hw.pSvga)
    268         {
    269             SvgaAdapterStop(pGaDevExt->hw.pSvga, &pDevExt->u.primary.DxgkInterface);
    270             pGaDevExt->hw.pSvga = NULL;
    271         }
    272 
    273         GaMemFree(pGaDevExt);
    274         pDevExt->pGa = NULL;
    275     }
    276 }
    277 
    278 NTSTATUS GaAdapterStart(PVBOXMP_DEVEXT pDevExt)
    279 {
    280     GALOG(("pDevExt = %p\n", pDevExt));
    281 
    282     NTSTATUS Status;
    283 
    284     if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
    285     {
    286         VBOXWDDM_EXT_GA *pGaDevExt = (VBOXWDDM_EXT_GA *)GaMemAllocZero(sizeof(*pGaDevExt));
    287         if (pGaDevExt)
    288         {
    289             /* Init fence objects. */
    290             pGaDevExt->fenceObjects.u32SeqNoSource = 0;
    291             RTListInit(&pGaDevExt->fenceObjects.list);
    292 
    293             KeInitializeSpinLock(&pGaDevExt->fenceObjects.SpinLock);
    294             RT_ZERO(pGaDevExt->fenceObjects.au32HandleBits);
    295             ASMBitSet(pGaDevExt->fenceObjects.au32HandleBits, 0); /* Exclude id==0, it is for NULL. */
    296 
    297             /* Start hardware. */
    298             Status = SvgaAdapterStart(&pGaDevExt->hw.pSvga, &pDevExt->u.primary.DxgkInterface,
    299                                       pDevExt->HwResources.phFIFO, pDevExt->HwResources.cbFIFO,
    300                                       pDevExt->HwResources.phIO, pDevExt->HwResources.cbIO);
    301             if (Status == STATUS_SUCCESS)
    302             {
    303                 pDevExt->pGa = pGaDevExt;
    304             }
    305         }
    306         else
    307         {
    308             Status = STATUS_INSUFFICIENT_RESOURCES;
    309         }
    310     }
    311     else
    312     {
    313         Status = STATUS_NOT_SUPPORTED;
    314     }
    315 
    316     if (Status != STATUS_SUCCESS)
    317     {
    318         GaAdapterStop(pDevExt);
    319     }
    320 
    321     return Status;
    322 }
    323 
    324 NTSTATUS GaQueryInfo(PVBOXWDDM_EXT_GA pGaDevExt,
    325                      VBOXVIDEO_HWTYPE enmHwType,
    326                      VBOXGAHWINFO *pHWInfo)
    327 {
    328     NTSTATUS Status = STATUS_SUCCESS;
    329 
    330     switch (enmHwType)
    331     {
    332         case VBOXVIDEO_HWTYPE_VMSVGA:
    333             pHWInfo->u32HwType = VBOX_GA_HW_TYPE_VMSVGA;
    334             break;
    335         default:
    336             Status = STATUS_NOT_SUPPORTED;
    337     }
    338 
    339     if (NT_SUCCESS(Status))
    340     {
    341         pHWInfo->u32Reserved = 0;
    342         RT_ZERO(pHWInfo->u.au8Raw);
    343 
    344         if (pHWInfo->u32HwType == VBOX_GA_HW_TYPE_VMSVGA)
    345         {
    346             Status = SvgaQueryInfo(pGaDevExt->hw.pSvga, &pHWInfo->u.svga);
    347         }
    348         else
    349         {
    350             Status = STATUS_NOT_SUPPORTED;
    351         }
    352     }
    353 
    354     return Status;
    355 }
    356 
    357 NTSTATUS GaDeviceCreate(PVBOXWDDM_EXT_GA pGaDevExt,
    358                         PVBOXWDDM_DEVICE pDevice)
    359 {
    360     RT_NOREF2(pGaDevExt, pDevice);
    361     return STATUS_SUCCESS;
    362 }
    363 
    364 void GaDeviceDestroy(PVBOXWDDM_EXT_GA pGaDevExt,
    365                      PVBOXWDDM_DEVICE pDevice)
    366 {
    367     /* Free fence objects and GMRs. This is useful when the application has crashed.. */
    368     gaFenceObjectsDestroy(pGaDevExt, pDevice);
    369     SvgaRegionsDestroy(pGaDevExt->hw.pSvga, pDevice);
    370 }
    371 
    372 NTSTATUS GaContextCreate(PVBOXWDDM_EXT_GA pGaDevExt,
    373                          PVBOXWDDM_CREATECONTEXT_INFO pInfo,
    374                          PVBOXWDDM_CONTEXT pContext)
    375 {
    376     AssertReturn(pContext->NodeOrdinal == 0, STATUS_NOT_SUPPORTED);
    377 
    378     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    379     uint32_t u32Cid;
    380     NTSTATUS Status = SvgaContextIdAlloc(pSvga, &u32Cid);
    381     if (NT_SUCCESS(Status))
    382     {
    383         Status = SvgaContextCreate(pSvga, u32Cid);
    384         if (Status == STATUS_SUCCESS)
    385         {
    386             /** @todo Save other pInfo fields. */
    387             RT_NOREF(pInfo);
    388 
    389             /* Init pContext fields, which are relevant to the gallium context. */
    390             pContext->u32Cid = u32Cid;
    391 
    392             GALOG(("pGaDevExt = %p, cid = %d\n", pGaDevExt, u32Cid));
    393         }
    394         else
    395         {
    396             SvgaContextIdFree(pSvga, u32Cid);
    397         }
    398     }
    399 
    400     return Status;
    401 }
    402 
    403 NTSTATUS GaContextDestroy(PVBOXWDDM_EXT_GA pGaDevExt,
    404                           PVBOXWDDM_CONTEXT pContext)
    405 {
    406     GALOG(("u32Cid = %d\n", pContext->u32Cid));
    407 
    408     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    409 
    410     SvgaContextDestroy(pSvga, pContext->u32Cid);
    411 
    412     return SvgaContextIdFree(pSvga, pContext->u32Cid);
    413 }
    414 
    415 NTSTATUS GaUpdate(PVBOXWDDM_EXT_GA pGaDevExt,
    416                   uint32_t u32X,
    417                   uint32_t u32Y,
    418                   uint32_t u32Width,
    419                   uint32_t u32Height)
    420 {
    421     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    422     return SvgaUpdate(pSvga, u32X, u32Y, u32Width, u32Height);
    423 }
    424 
    425 static NTSTATUS gaSurfaceDefine(PVBOXWDDM_EXT_GA pGaDevExt,
    426                                 GASURFCREATE *pCreateParms,
    427                                 GASURFSIZE *paSizes,
    428                                 uint32_t cSizes,
    429                                 uint32_t *pu32Sid)
    430 {
    431     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    432 
    433     uint32_t u32Sid;
    434     NTSTATUS Status = SvgaSurfaceIdAlloc(pSvga, &u32Sid);
    435     if (NT_SUCCESS(Status))
    436     {
    437         Status = SvgaSurfaceDefine(pSvga, pCreateParms, paSizes, cSizes, u32Sid);
    438         if (NT_SUCCESS(Status))
    439         {
    440             *pu32Sid = u32Sid;
    441         }
    442         else
    443         {
    444             SvgaSurfaceIdFree(pSvga, u32Sid);
    445         }
    446     }
    447     else
    448     {
    449         Status = STATUS_INSUFFICIENT_RESOURCES;
    450     }
    451 
    452     return Status;
    453 }
    454 
    455 static NTSTATUS gaSurfaceDestroy(PVBOXWDDM_EXT_GA pGaDevExt,
    456                                  uint32_t u32Sid)
    457 {
    458     VBOXWDDM_EXT_VMSVGA *pSvga = pGaDevExt->hw.pSvga;
    459 
    460     NTSTATUS Status = SvgaSurfaceDestroy(pSvga, u32Sid);
    461     if (NT_SUCCESS(Status))
    462     {
    463         SvgaSurfaceIdFree(pSvga, u32Sid);
    464     }
    465 
    466     return Status;
    467 }
    468 
    469 NTSTATUS GaScreenDefine(PVBOXWDDM_EXT_GA pGaDevExt,
    470                         uint32_t u32Offset,
    471                         uint32_t u32ScreenId,
    472                         int32_t xOrigin,
    473                         int32_t yOrigin,
    474                         uint32_t u32Width,
    475                         uint32_t u32Height,
    476                         bool fBlank)
    477 {
    478     return SvgaScreenDefine(pGaDevExt->hw.pSvga, u32Offset, u32ScreenId, xOrigin, yOrigin, u32Width, u32Height, fBlank);
    479 }
    480 
    481 NTSTATUS GaScreenDestroy(PVBOXWDDM_EXT_GA pGaDevExt,
    482                          uint32_t u32ScreenId)
    483 {
    484     return SvgaScreenDestroy(pGaDevExt->hw.pSvga, u32ScreenId);
    485 }
    486 
    487 static NTSTATUS gaSharedSidInsert(PVBOXWDDM_EXT_GA pGaDevExt,
    488                                   uint32_t u32Sid,
    489                                   uint32_t u32SharedSid)
    490 {
    491     GASHAREDSID *pNode = (GASHAREDSID *)GaMemAllocZero(sizeof(GASHAREDSID));
    492     if (!pNode)
    493         return STATUS_INSUFFICIENT_RESOURCES;
    494     return SvgaSharedSidInsert(pGaDevExt->hw.pSvga, pNode, u32Sid, u32SharedSid);
    495 }
    496 
    497 static NTSTATUS gaSharedSidRemove(PVBOXWDDM_EXT_GA pGaDevExt,
    498                                   uint32_t u32Sid)
    499 {
    500     GASHAREDSID *pNode = SvgaSharedSidRemove(pGaDevExt->hw.pSvga, u32Sid);
    501     if (pNode)
    502         GaMemFree(pNode);
    503     return STATUS_SUCCESS;
    504 }
    505 
    506 
    507 /*
    508  * Fence objects.
    509  */
    510 
    511 NTSTATUS GaFenceCreate(PVBOXWDDM_EXT_GA pGaDevExt,
    512                        PVBOXWDDM_DEVICE pDevice,
    513                        uint32_t *pu32FenceHandle)
    514 {
    515     GAFENCEOBJECT *pFO = (GAFENCEOBJECT *)GaMemAllocZero(sizeof(GAFENCEOBJECT));
    516     if (!pFO)
    517         return STATUS_INSUFFICIENT_RESOURCES;
    518 
    519     /* pFO->cRefs             = 0; */
    520     pFO->u32FenceState      = GAFENCE_STATE_IDLE;
    521     /* pFO->fu32FenceFlags    = 0; */
    522     /* pFO->u32SubmissionFenceId    = 0; */
    523     pFO->u32SeqNo           = ASMAtomicIncU32(&pGaDevExt->fenceObjects.u32SeqNoSource);
    524     pFO->pDevice            = pDevice;
    525     /* RT_ZERO(pFO->event); */
    526 
    527     gaFenceObjectsLock(pGaDevExt);
    528 
    529     NTSTATUS Status = GaIdAlloc(pGaDevExt->fenceObjects.au32HandleBits, sizeof(pGaDevExt->fenceObjects.au32HandleBits),
    530                                 VBOXWDDM_GA_MAX_FENCE_OBJECTS, &pFO->u32FenceHandle);
    531     if (NT_SUCCESS(Status))
    532     {
    533         RTListAppend(&pGaDevExt->fenceObjects.list, &pFO->node);
    534         gaFenceRef(pFO);
    535 
    536         gaFenceObjectsUnlock(pGaDevExt);
    537 
    538         *pu32FenceHandle = pFO->u32FenceHandle;
    539 
    540         GALOG(("u32FenceHandle = %d\n", pFO->u32FenceHandle));
    541         return STATUS_SUCCESS;
    542     }
    543 
    544     /* Failure */
    545     gaFenceObjectsUnlock(pGaDevExt);
    546     GaMemFree(pFO);
    547     return Status;
    548 }
    549 
    550 NTSTATUS GaFenceQuery(PVBOXWDDM_EXT_GA pGaDevExt,
    551                       uint32_t u32FenceHandle,
    552                       uint32_t *pu32SubmittedSeqNo,
    553                       uint32_t *pu32ProcessedSeqNo,
    554                       uint32_t *pu32FenceStatus)
    555 {
    556     gaFenceObjectsLock(pGaDevExt);
    557 
    558     GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
    559 
    560     gaFenceObjectsUnlock(pGaDevExt);
    561 
    562     GALOG(("u32FenceHandle = %d, pFO %p\n", u32FenceHandle, pFO));
    563     if (pFO)
    564     {
    565         *pu32SubmittedSeqNo = pFO->u32SeqNo;
    566         switch (pFO->u32FenceState)
    567         {
    568             default:
    569                 AssertFailed();
    570                 RT_FALL_THRU();
    571             case GAFENCE_STATE_IDLE:      *pu32FenceStatus = GA_FENCE_STATUS_IDLE;      break;
    572             case GAFENCE_STATE_SUBMITTED: *pu32FenceStatus = GA_FENCE_STATUS_SUBMITTED; break;
    573             case GAFENCE_STATE_SIGNALED:  *pu32FenceStatus = GA_FENCE_STATUS_SIGNALED;  break;
    574         }
    575 
    576         gaFenceUnref(pGaDevExt, pFO);
    577     }
    578     else
    579     {
    580         *pu32SubmittedSeqNo = 0;
    581         *pu32FenceStatus = GA_FENCE_STATUS_NULL;
    582     }
    583     *pu32ProcessedSeqNo = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedSeqNo);
    584 
    585     return STATUS_SUCCESS;
    586 }
    587 
    588 NTSTATUS GaFenceWait(PVBOXWDDM_EXT_GA pGaDevExt,
    589                      uint32_t u32FenceHandle,
    590                      uint32_t u32TimeoutUS)
    591 {
    592     gaFenceObjectsLock(pGaDevExt);
    593 
    594     GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
    595     AssertReturnStmt(pFO, gaFenceObjectsUnlock(pGaDevExt), STATUS_INVALID_PARAMETER);
    596 
    597     if (pFO->u32FenceState == GAFENCE_STATE_SIGNALED)
    598     {
    599         /* Already signaled. */
    600         gaFenceObjectsUnlock(pGaDevExt);
    601         gaFenceUnref(pGaDevExt, pFO);
    602         return STATUS_SUCCESS;
    603     }
    604 
    605     /* Wait */
    606     if (!RT_BOOL(pFO->fu32FenceFlags & GAFENCE_F_WAITED))
    607     {
    608         KeInitializeEvent(&pFO->event, NotificationEvent, FALSE);
    609         pFO->fu32FenceFlags |= GAFENCE_F_WAITED;
    610     }
    611 
    612     gaFenceObjectsUnlock(pGaDevExt);
    613 
    614     GALOG(("u32FenceHandle = %d, pFO %p\n", u32FenceHandle, pFO));
    615 
    616     LARGE_INTEGER Timeout;
    617     Timeout.QuadPart = u32TimeoutUS;
    618     Timeout.QuadPart *= -10LL; /* Microseconds to relative 100-nanoseconds units. */
    619     NTSTATUS Status = KeWaitForSingleObject(&pFO->event, UserRequest, KernelMode, TRUE, &Timeout);
    620 
    621     gaFenceUnref(pGaDevExt, pFO);
    622 
    623     return Status;
    624 }
    625 
    626 NTSTATUS GaFenceUnref(PVBOXWDDM_EXT_GA pGaDevExt,
    627                       uint32_t u32FenceHandle)
    628 {
    629     gaFenceObjectsLock(pGaDevExt);
    630 
    631     GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
    632     AssertReturnStmt(pFO, gaFenceObjectsUnlock(pGaDevExt), STATUS_INVALID_PARAMETER);
    633 
    634     if (RT_BOOL(pFO->fu32FenceFlags & GAFENCE_F_WAITED))
    635     {
    636         KeSetEvent(&pFO->event, 0, FALSE);
    637         pFO->fu32FenceFlags &= ~GAFENCE_F_WAITED;
    638     }
    639 
    640     gaFenceObjectsUnlock(pGaDevExt);
    641 
    642     GALOG(("u32FenceHandle = %d, pFO %p\n", u32FenceHandle, pFO));
    643 
    644     /* Undo gaFenceLookup ref. */
    645     gaFenceUnref(pGaDevExt, pFO);
    646 
    647     /* Undo the GaFenceCreate ref. */
    648     gaFenceUnref(pGaDevExt, pFO);
    649 
    650     return STATUS_SUCCESS;
    651 }
    652 
    653 static NTSTATUS gaPresent(PVBOXWDDM_EXT_GA pGaDevExt,
    654                           uint32_t u32Sid,
    655                           uint32_t u32Width,
    656                           uint32_t u32Height,
    657                           uint32_t u32VRAMOffset)
    658 {
    659     return SvgaPresentVRAM(pGaDevExt->hw.pSvga, u32Sid, u32Width, u32Height, u32VRAMOffset);
    660 }
    661 
    662 static int gaFenceCmp(uint32_t u32FenceA, uint32_t u32FenceB)
    663 {
    664      if (   u32FenceA < u32FenceB
    665          || u32FenceA - u32FenceB > UINT32_MAX / 2)
    666      {
    667          return -1; /* FenceA is newer than FenceB. */
    668      }
    669      else if (u32FenceA == u32FenceB)
    670      {
    671          /* FenceA is equal to FenceB. */
    672          return 0;
    673      }
    674 
    675      /* FenceA is older than FenceB. */
    676      return 1;
    677 }
    678 
    679 
    680 static void dxgkNotifyDma(DXGKRNL_INTERFACE *pDxgkInterface,
    681                           DXGK_INTERRUPT_TYPE enmType,
    682                           UINT uNodeOrdinal,
    683                           UINT uFenceId,
    684                           UINT uLastCompletedFenceId)
    685 {
    686     DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
    687     memset(&notify, 0, sizeof(notify));
    688 
    689     GALOG(("%d fence %d\n", enmType, uFenceId));
    690     switch (enmType)
    691     {
    692         case DXGK_INTERRUPT_DMA_COMPLETED:
    693             notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
    694             notify.DmaCompleted.SubmissionFenceId = uFenceId;
    695             notify.DmaCompleted.NodeOrdinal = uNodeOrdinal;
    696             break;
    697 
    698         case DXGK_INTERRUPT_DMA_PREEMPTED:
    699             notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
    700             notify.DmaPreempted.PreemptionFenceId = uFenceId;
    701             notify.DmaPreempted.NodeOrdinal = uNodeOrdinal;
    702             notify.DmaPreempted.LastCompletedFenceId = uLastCompletedFenceId;
    703             break;
    704 
    705         case DXGK_INTERRUPT_DMA_FAULTED:
    706             notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
    707             notify.DmaFaulted.FaultedFenceId = uFenceId;
    708             notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL;
    709             notify.DmaFaulted.NodeOrdinal = uNodeOrdinal;
    710             break;
    711 
    712         default:
    713             WARN(("completion type %d", enmType));
    714             break;
    715     }
    716 
    717     if (notify.InterruptType)
    718     {
    719         pDxgkInterface->DxgkCbNotifyInterrupt(pDxgkInterface->DeviceHandle, &notify);
    720         GALOG(("notified\n"));
    721     }
    722 }
    723 
    724 static void gaReportFence(PVBOXMP_DEVEXT pDevExt)
    725 {
    726     /* Runs at device interrupt IRQL. */
    727     Assert(KeGetCurrentIrql() > DISPATCH_LEVEL);
    728 
    729     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    730     AssertReturnVoid(pGaDevExt);
    731 
    732     PVBOXWDDM_EXT_VMSVGA pSvga = pGaDevExt->hw.pSvga;
    733     AssertReturnVoid(pSvga);
    734 
    735     /* Read the last completed fence from the device. */
    736     const uint32_t u32Fence = SVGAFifoRead(pSvga, SVGA_FIFO_FENCE);
    737     GALOG(("Fence %u\n", u32Fence));
    738 
    739     if (u32Fence == ASMAtomicReadU32(&pGaDevExt->u32PreemptionFenceId))
    740     {
    741         ASMAtomicWriteU32(&pGaDevExt->u32PreemptionFenceId, 0);
    742 
    743         const uint32_t u32LastSubmittedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastSubmittedFenceId);
    744         ASMAtomicWriteU32(&pGaDevExt->u32LastCompletedFenceId, u32LastSubmittedFenceId);
    745 
    746         dxgkNotifyDma(&pDevExt->u.primary.DxgkInterface, DXGK_INTERRUPT_DMA_PREEMPTED,
    747                       0, u32Fence, u32LastSubmittedFenceId);
    748 
    749         /* Notify DXGK about the updated DMA fence. */
    750         pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
    751     }
    752     else
    753     {
    754         /* Check if we already reported it. */
    755         const uint32_t u32LastCompletedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedFenceId);
    756         if (gaFenceCmp(u32LastCompletedFenceId, u32Fence) < 0)
    757         {
    758             /* u32Fence is newer. */
    759             ASMAtomicWriteU32(&pGaDevExt->u32LastCompletedFenceId, u32Fence);
    760 
    761             dxgkNotifyDma(&pDevExt->u.primary.DxgkInterface, DXGK_INTERRUPT_DMA_COMPLETED,
    762                           0, u32Fence, u32Fence);
    763 
    764             /* Notify DXGK about the updated DMA fence. */
    765             pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
    766         }
    767     }
    768 }
    769 
    770 /*
    771  * Description of DMA buffer content.
    772  * These structures are stored in DmaBufferPrivateData.
    773  */
    774 typedef struct GARENDERDATA
    775 {
    776     uint32_t      u32DataType;    /* GARENDERDATA_TYPE_* */
    777     uint32_t      cbData;         /* How many bytes. */
    778     GAFENCEOBJECT *pFenceObject;  /* User mode fence associated with this command buffer. */
    779     void          *pvDmaBuffer;   /* Pointer to the DMA buffer. */
    780 } GARENDERDATA;
    781 
    782 #define GARENDERDATA_TYPE_RENDER   1
    783 #define GARENDERDATA_TYPE_PRESENT  2
    784 #define GARENDERDATA_TYPE_PAGING   3
    785 #define GARENDERDATA_TYPE_FENCE    4
    786 
    787 /* If there are no commands but we need to trigger fence submission anyway, then submit a buffer of this size. */
    788 #define GA_DMA_MIN_SUBMIT_SIZE 4
    789 AssertCompile(GA_DMA_MIN_SUBMIT_SIZE < sizeof(SVGA3dCmdHeader));
    790 
    791 DECLINLINE(PVBOXWDDM_ALLOCATION) vboxWddmGetAllocationFromAllocList(DXGK_ALLOCATIONLIST *pAllocList)
    792 {
    793     PVBOXWDDM_OPENALLOCATION pOa = (PVBOXWDDM_OPENALLOCATION)pAllocList->hDeviceSpecificAllocation;
    794     return pOa? pOa->pAllocation: NULL;
    795 }
    796 
    797 static NTSTATUS gaGMRFBToVRAMSurface(DXGKARG_PRESENT *pPresent,
    798                                      PVBOXWDDM_EXT_VMSVGA pSvga,
    799                                      uint32_t idxAllocation,
    800                                      DXGK_ALLOCATIONLIST *pAllocationList,
    801                                      PVBOXWDDM_ALLOCATION pAllocation,
    802                                      uint8_t *pu8Target, uint32_t cbTarget, uint32_t *pu32TargetOut)
    803 {
    804     NTSTATUS Status = SvgaGenDefineGMRFB(pSvga,
    805                                          pAllocationList->SegmentId != 0 ?
    806                                              pAllocationList->PhysicalAddress.LowPart : 0,
    807                                          pAllocation->AllocData.SurfDesc.pitch,
    808                                          pu8Target, cbTarget, pu32TargetOut);
    809     if (Status == STATUS_SUCCESS)
    810     {
    811         /* Always tell WDDM that the SHADOWSURFACE must be "paged in". */
    812         UINT PatchOffset =   (uintptr_t)pu8Target - (uintptr_t)pPresent->pDmaBuffer
    813                            + sizeof(uint32_t)
    814                            + RT_UOFFSETOF(SVGAFifoCmdDefineGMRFB, ptr.offset);
    815 
    816         memset(pPresent->pPatchLocationListOut, 0, sizeof(D3DDDI_PATCHLOCATIONLIST));
    817         pPresent->pPatchLocationListOut->AllocationIndex = idxAllocation;
    818         pPresent->pPatchLocationListOut->PatchOffset = PatchOffset;
    819         ++pPresent->pPatchLocationListOut;
    820     }
    821     return Status;
    822 }
    823 
    824 /** Generate commands for Blt case.
    825  *
    826  * @return Status code.
    827  * @param pPresent          Information about rectangles to blit.
    828  * @param pSvga             VMSVGA device extension.
    829  * @param pSrc              Source allocation description.
    830  * @param pSrcAlloc         Allocation to blit from.
    831  * @param pDst              Destination allocation description.
    832  * @param pDstAlloc         Allocation to blit to.
    833  * @param pu8Target         Command buffer to fill.
    834  * @param cbTarget          Size of command buffer.
    835  * @param pu32TargetOut     Where to store size of generated commands.
    836  */
    837 static NTSTATUS gaPresentBlt(DXGKARG_PRESENT *pPresent,
    838                              PVBOXWDDM_EXT_VMSVGA pSvga,
    839                              DXGK_ALLOCATIONLIST *pSrc,
    840                              PVBOXWDDM_ALLOCATION pSrcAlloc,
    841                              DXGK_ALLOCATIONLIST *pDst,
    842                              PVBOXWDDM_ALLOCATION pDstAlloc,
    843                              uint8_t *pu8Target, uint32_t cbTarget, uint32_t *pu32TargetOut)
    844 {
    845     NTSTATUS Status = STATUS_SUCCESS;
    846 
    847     uint8_t * const pu8TargetStart = pu8Target;
    848 
    849     uint32_t cbCmd = 0;
    850 
    851     /** @todo One subrect at a time for now, consider passing all pDstSubRects when possible,
    852      * for example in one BlitSurfaceToScreen.
    853      */
    854     uint32_t iSubRect;
    855     for (iSubRect = pPresent->MultipassOffset; iSubRect < pPresent->SubRectCnt; ++iSubRect)
    856     {
    857         /* DstSubRects are in Dst coords.
    858          * To calculate corresponding SrcSubRect:
    859          *    srcsub = src + (dstsub - dst) = dstsub + (src - dst).
    860          * Precompute the src - dst differences to use in the code below.
    861          */
    862         int32_t const dx = pPresent->SrcRect.left - pPresent->DstRect.left;
    863         int32_t const dy = pPresent->SrcRect.top  - pPresent->DstRect.top;
    864 
    865         if (iSubRect == 0)
    866         {
    867             if (   pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
    868                 || pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE)
    869             {
    870                 /* Define GMRFB to point to the shadow/staging surface. */
    871                 Status = gaGMRFBToVRAMSurface(pPresent, pSvga,
    872                                               DXGK_PRESENT_SOURCE_INDEX, pSrc, pSrcAlloc,
    873                                               pu8Target, cbTarget, &cbCmd);
    874             }
    875             else if (   pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
    876                      || pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE)
    877             {
    878                 /* Define GMRFB to point to the shadow/staging surface. */
    879                 Status = gaGMRFBToVRAMSurface(pPresent, pSvga,
    880                                               DXGK_PRESENT_DESTINATION_INDEX, pDst, pDstAlloc,
    881                                               pu8Target, cbTarget, &cbCmd);
    882             }
    883 
    884             if (Status == STATUS_BUFFER_OVERFLOW)
    885             {
    886                 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    887                 break;
    888             }
    889 
    890             pu8Target += cbCmd;
    891             cbTarget -= cbCmd;
    892         }
    893 
    894         if (pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE)
    895         {
    896             /* To screen. */
    897             if (   pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
    898                 || pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE)
    899             {
    900                 /* From GDI software drawing surface. */
    901                 GALOG(("Blt: SHADOWSURFACE(%d) 0x%08X -> SHAREDPRIMARYSURFACE 0x%08X\n",
    902                        pSrcAlloc->enmType, pSrc->PhysicalAddress.LowPart, pDst->PhysicalAddress.LowPart));
    903 
    904                 int32_t const xSrc = pPresent->pDstSubRects[iSubRect].left + dx;
    905                 int32_t const ySrc = pPresent->pDstSubRects[iSubRect].top  + dy;
    906                 Status = SvgaGenBlitGMRFBToScreen(pSvga,
    907                                                   pDstAlloc->AllocData.SurfDesc.VidPnSourceId,
    908                                                   xSrc, ySrc,
    909                                                   &pPresent->pDstSubRects[iSubRect],
    910                                                   pu8Target, cbTarget, &cbCmd);
    911             }
    912             else if (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC)
    913             {
    914                 /* From a surface. */
    915                 GALOG(("Blt: surface id 0x%08X -> SHAREDPRIMARYSURFACE 0x%08X\n",
    916                        pSrcAlloc->AllocData.hostID, pDst->PhysicalAddress.LowPart));
    917 
    918                 RECT const dstRect = pPresent->pDstSubRects[iSubRect];
    919                 RECT srcRect;
    920                 srcRect.left   = dstRect.left   + dx;
    921                 srcRect.top    = dstRect.top    + dy;
    922                 srcRect.right  = dstRect.right  + dx;
    923                 srcRect.bottom = dstRect.bottom + dy;
    924                 RECT clipRect = dstRect;
    925                 Status = SvgaGenBlitSurfaceToScreen(pSvga,
    926                                                     pSrcAlloc->AllocData.hostID,
    927                                                     &srcRect,
    928                                                     pDstAlloc->AllocData.SurfDesc.VidPnSourceId,
    929                                                     &dstRect,
    930                                                     1, &clipRect,
    931                                                     pu8Target, cbTarget, &cbCmd, NULL);
    932             }
    933             else
    934             {
    935                 AssertFailed();
    936             }
    937         }
    938         else if (  pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
    939                 || pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE)
    940         {
    941             /* To GDI software drawing surface. */
    942             if (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE)
    943             {
    944                 /* From screen. */
    945                 GALOG(("Blt: SHAREDPRIMARYSURFACE 0x%08X -> SHADOWSURFACE(%d) 0x%08X\n",
    946                        pSrc->PhysicalAddress.LowPart, pDstAlloc->enmType, pDst->PhysicalAddress.LowPart));
    947 
    948                 int32_t const xSrc = pPresent->pDstSubRects[iSubRect].left + dx;
    949                 int32_t const ySrc = pPresent->pDstSubRects[iSubRect].top  + dy;
    950 
    951                 Status = SvgaGenBlitScreenToGMRFB(pSvga,
    952                                                   pSrcAlloc->AllocData.SurfDesc.VidPnSourceId,
    953                                                   xSrc, ySrc,
    954                                                   &pPresent->pDstSubRects[iSubRect],
    955                                                   pu8Target, cbTarget, &cbCmd);
    956             }
    957             else if (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC)
    958             {
    959                 /* From a surface. */
    960                 GALOG(("Blt: surface id 0x%08X -> SHADOWSURFACE(%d) %d:0x%08X\n",
    961                        pSrcAlloc->AllocData.hostID, pDstAlloc->enmType, pDst->SegmentId, pDst->PhysicalAddress.LowPart));
    962 
    963                 SVGAGuestImage guestImage;
    964                 guestImage.ptr.gmrId  = SVGA_GMR_FRAMEBUFFER;
    965                 guestImage.ptr.offset = pDst->SegmentId != 0 ?  pDst->PhysicalAddress.LowPart : 0;
    966                 guestImage.pitch      = pDstAlloc->AllocData.SurfDesc.pitch;
    967 
    968                 SVGA3dSurfaceImageId surfId;
    969                 surfId.sid    = pSrcAlloc->AllocData.hostID;
    970                 surfId.face   = 0;
    971                 surfId.mipmap = 0;
    972 
    973                 int32_t const xSrc = pPresent->pDstSubRects[iSubRect].left + dx;
    974                 int32_t const ySrc = pPresent->pDstSubRects[iSubRect].top  + dy;
    975 
    976                 Status = SvgaGenSurfaceDMA(pSvga,
    977                                            &guestImage, &surfId, SVGA3D_READ_HOST_VRAM,
    978                                            xSrc, ySrc,
    979                                            pPresent->pDstSubRects[iSubRect].left,
    980                                            pPresent->pDstSubRects[iSubRect].top,
    981                                            pPresent->pDstSubRects[iSubRect].right - pPresent->pDstSubRects[iSubRect].left,
    982                                            pPresent->pDstSubRects[iSubRect].bottom - pPresent->pDstSubRects[iSubRect].top,
    983                                            pu8Target, cbTarget, &cbCmd);
    984                 if (Status == STATUS_SUCCESS)
    985                 {
    986                     /* Always tell WDDM that the SHADOWSURFACE must be "paged in". */
    987                     UINT PatchOffset =   (uintptr_t)pu8Target - (uintptr_t)pPresent->pDmaBuffer
    988                                        + sizeof(SVGA3dCmdHeader)
    989                                        + RT_UOFFSETOF(SVGA3dCmdSurfaceDMA, guest.ptr.offset);
    990 
    991                     memset(pPresent->pPatchLocationListOut, 0, sizeof(D3DDDI_PATCHLOCATIONLIST));
    992                     pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX;
    993                     pPresent->pPatchLocationListOut->PatchOffset = PatchOffset;
    994                     ++pPresent->pPatchLocationListOut;
    995                 }
    996             }
    997             else
    998             {
    999                 AssertFailed();
    1000             }
    1001         }
    1002         else
    1003             AssertFailed();
    1004 
    1005         if (Status == STATUS_BUFFER_OVERFLOW)
    1006         {
    1007             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1008             break;
    1009         }
    1010 
    1011         pu8Target += cbCmd;
    1012         cbTarget -= cbCmd;
    1013     }
    1014 
    1015     *pu32TargetOut = (uintptr_t)pu8Target - (uintptr_t)pu8TargetStart;
    1016 
    1017     if (Status == STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER)
    1018     {
    1019         pPresent->MultipassOffset = iSubRect;
    1020     }
    1021 
    1022     return Status;
    1023 }
    1024 
    1025 NTSTATUS APIENTRY GaDxgkDdiPresent(const HANDLE hContext,
    1026                                    DXGKARG_PRESENT *pPresent)
    1027 {
    1028     NTSTATUS Status = STATUS_SUCCESS;
    1029     PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
    1030     PVBOXWDDM_DEVICE pDevice = pContext->pDevice;
    1031     PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
    1032 
    1033     DXGK_ALLOCATIONLIST *pSrc =  &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX];
    1034     DXGK_ALLOCATIONLIST *pDst =  &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX];
    1035 
    1036     if (pPresent->Flags.Blt)
    1037     {
    1038         PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pSrc);
    1039         PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDst);
    1040 
    1041         GALOG(("Blt: sid=%x -> sid=%x\n", pSrcAlloc->AllocData.hostID, pDstAlloc->AllocData.hostID));
    1042 
    1043         /** @todo Review standard allocations (DxgkDdiGetStandardAllocationDriverData, etc).
    1044          *        Probably can be used more naturally with VMSVGA.
    1045          */
    1046 
    1047         /** @todo Merge common code for all branches (Blt, Flip, ColorFill) */
    1048 
    1049         /* Generate DMA buffer containing the SVGA_CMD_BLIT_GMRFB_TO_SCREEN commands.
    1050          * Store the command buffer descriptor to pDmaBufferPrivateData.
    1051          */
    1052         GARENDERDATA *pRenderData = NULL;
    1053         uint32_t u32TargetLength = 0;
    1054         uint32_t cbPrivateData = 0;
    1055 
    1056         if (pPresent->DmaBufferPrivateDataSize >= sizeof(GARENDERDATA))
    1057         {
    1058             uint8_t *pu8Target = (uint8_t *)pPresent->pDmaBuffer;
    1059             uint32_t cbTarget = pPresent->DmaSize;
    1060 
    1061             Status = gaPresentBlt(pPresent, pDevExt->pGa->hw.pSvga, pSrc, pSrcAlloc, pDst, pDstAlloc,
    1062                                   pu8Target, cbTarget, &u32TargetLength);
    1063 
    1064             /* Fill RenderData description in any case, it will be ignored if the above code failed. */
    1065             pRenderData = (GARENDERDATA *)pPresent->pDmaBufferPrivateData;
    1066             pRenderData->u32DataType  = GARENDERDATA_TYPE_PRESENT;
    1067             pRenderData->cbData       = u32TargetLength;
    1068             pRenderData->pFenceObject = NULL; /* Not a user request, so no user accessible fence object. */
    1069             pRenderData->pvDmaBuffer  = pPresent->pDmaBuffer;
    1070             cbPrivateData = sizeof(GARENDERDATA);
    1071         }
    1072         else
    1073         {
    1074             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1075         }
    1076 
    1077         switch (Status)
    1078         {
    1079             case STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER:
    1080                 if (pRenderData == NULL)
    1081                 {
    1082                     /* Not enough space in pDmaBufferPrivateData. */
    1083                     break;
    1084                 }
    1085                 RT_FALL_THRU();
    1086             case STATUS_SUCCESS:
    1087             {
    1088                 if (u32TargetLength)
    1089                 {
    1090                     pPresent->pDmaBuffer = (uint8_t *)pPresent->pDmaBuffer + u32TargetLength;
    1091                     pPresent->pDmaBufferPrivateData = (uint8_t *)pPresent->pDmaBufferPrivateData + cbPrivateData;
    1092                 }
    1093             } break;
    1094             default: break;
    1095         }
    1096     }
    1097     else if (pPresent->Flags.Flip)
    1098     {
    1099         PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pSrc);
    1100 
    1101         GALOG(("Flip: sid=%x %dx%d\n",
    1102                pSrcAlloc->AllocData.hostID, pSrcAlloc->AllocData.SurfDesc.width, pSrcAlloc->AllocData.SurfDesc.height));
    1103 
    1104         GALOG(("Flip: %d,%d %d,%d -> %d,%d %d,%d subrects %d\n",
    1105                pPresent->SrcRect.left, pPresent->SrcRect.top, pPresent->SrcRect.right, pPresent->SrcRect.bottom,
    1106                pPresent->DstRect.left, pPresent->DstRect.top, pPresent->DstRect.right, pPresent->DstRect.bottom,
    1107                pPresent->SubRectCnt));
    1108         uint32_t iSubRect;
    1109         for (iSubRect = 0; iSubRect < pPresent->SubRectCnt; ++iSubRect)
    1110         {
    1111             GALOG(("Flip[%d]: %d,%d %d,%d\n",
    1112                    pPresent->pDstSubRects[iSubRect].left, pPresent->pDstSubRects[iSubRect].top,
    1113                    pPresent->pDstSubRects[iSubRect].right, pPresent->pDstSubRects[iSubRect].bottom,
    1114                    iSubRect));
    1115         }
    1116 
    1117         /* Generate DMA buffer containing the present commands.
    1118          * Store the command buffer descriptor to pDmaBufferPrivateData.
    1119          */
    1120         GARENDERDATA *pRenderData = NULL;
    1121         uint32_t u32TargetLength = 0;
    1122         uint32_t cbPrivateData = 0;
    1123 
    1124         if (pPresent->DmaBufferPrivateDataSize >= sizeof(GARENDERDATA))
    1125         {
    1126             void *pvTarget          = pPresent->pDmaBuffer;
    1127             const uint32_t cbTarget = pPresent->DmaSize;
    1128             if (cbTarget > GA_DMA_MIN_SUBMIT_SIZE)
    1129             {
    1130 #if 1
    1131                 /* SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN */
    1132                 RECT rect;
    1133                 rect.left   = 0;
    1134                 rect.top    = 0;
    1135                 rect.right  = pSrcAlloc->AllocData.SurfDesc.width;
    1136                 rect.bottom = pSrcAlloc->AllocData.SurfDesc.height;
    1137                 uint32_t const cInClipRects = pPresent->SubRectCnt - pPresent->MultipassOffset;
    1138                 uint32_t cOutClipRects = 0;
    1139                 Status = SvgaGenBlitSurfaceToScreen(pDevExt->pGa->hw.pSvga,
    1140                                                     pSrcAlloc->AllocData.hostID,
    1141                                                     &rect,
    1142                                                     pSrcAlloc->AllocData.SurfDesc.VidPnSourceId,
    1143                                                     &rect,
    1144                                                     cInClipRects,
    1145                                                     pPresent->pDstSubRects + pPresent->MultipassOffset,
    1146                                                     pvTarget, cbTarget, &u32TargetLength, &cOutClipRects);
    1147                 if (Status == STATUS_BUFFER_OVERFLOW)
    1148                 {
    1149                     Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1150                 }
    1151 
    1152                 if (Status == STATUS_SUCCESS)
    1153                 {
    1154                     if (cOutClipRects < cInClipRects)
    1155                     {
    1156                         /* Not all rectangles were copied. */
    1157                         Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1158                     }
    1159 
    1160                     /* Advance the current rectangle index. */
    1161                     pPresent->MultipassOffset += cOutClipRects;
    1162                 }
    1163 #else
    1164                 /* This tests the SVGA_3D_CMD_PRESENT command. */
    1165                 RT_NOREF(pDevExt);
    1166                 Status = SvgaGenPresent(pSrcAlloc->AllocData.hostID,
    1167                                         pSrcAlloc->AllocData.SurfDesc.width,
    1168                                         pSrcAlloc->AllocData.SurfDesc.height,
    1169                                         pvTarget, cbTarget, &u32TargetLength);
    1170                 if (Status == STATUS_BUFFER_OVERFLOW)
    1171                 {
    1172                     Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1173                 }
    1174 #endif
    1175             }
    1176             else
    1177             {
    1178                 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1179             }
    1180 
    1181             /* Fill RenderData description in any case, it will be ignored if the above code failed. */
    1182             pRenderData = (GARENDERDATA *)pPresent->pDmaBufferPrivateData;
    1183             pRenderData->u32DataType  = GARENDERDATA_TYPE_PRESENT;
    1184             pRenderData->cbData       = u32TargetLength;
    1185             pRenderData->pFenceObject = NULL; /* Not a user request, so no user accessible fence object. */
    1186             pRenderData->pvDmaBuffer = pPresent->pDmaBuffer;
    1187             cbPrivateData = sizeof(GARENDERDATA);
    1188         }
    1189         else
    1190         {
    1191             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1192         }
    1193 
    1194         switch (Status)
    1195         {
    1196             case STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER:
    1197                 if (pRenderData == NULL)
    1198                 {
    1199                     /* Not enough space in pDmaBufferPrivateData. */
    1200                     break;
    1201                 }
    1202                 RT_FALL_THRU();
    1203             case STATUS_SUCCESS:
    1204             {
    1205                 if (u32TargetLength)
    1206                 {
    1207                     pPresent->pDmaBuffer = (uint8_t *)pPresent->pDmaBuffer + u32TargetLength;
    1208                     pPresent->pDmaBufferPrivateData = (uint8_t *)pPresent->pDmaBufferPrivateData + cbPrivateData;
    1209                 }
    1210             } break;
    1211             default: break;
    1212         }
    1213     }
    1214     else if (pPresent->Flags.ColorFill)
    1215     {
    1216         GALOG(("ColorFill\n"));
    1217         AssertFailed();
    1218     }
    1219     else
    1220     {
    1221         WARN(("cmd NOT IMPLEMENTED!! Flags(0x%x)", pPresent->Flags.Value));
    1222         Status = STATUS_NOT_SUPPORTED;
    1223     }
    1224 
    1225     return Status;
    1226 }
    1227 
    1228 NTSTATUS APIENTRY GaDxgkDdiRender(const HANDLE hContext, DXGKARG_RENDER *pRender)
    1229 {
    1230     PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
    1231     PVBOXWDDM_DEVICE pDevice = pContext->pDevice;
    1232     PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
    1233     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1234 
    1235     AssertReturn(pContext && pContext->enmType == VBOXWDDM_CONTEXT_TYPE_GA_3D, STATUS_INVALID_PARAMETER);
    1236     AssertReturn(pRender->CommandLength > pRender->MultipassOffset, STATUS_INVALID_PARAMETER);
    1237     /* Expect 32 bit handle at the start of the command buffer. */
    1238     AssertReturn(pRender->CommandLength >= sizeof(uint32_t), STATUS_INVALID_PARAMETER);
    1239 
    1240     GARENDERDATA *pRenderData = NULL;  /* Pointer to the DMA buffer description. */
    1241     uint32_t cbPrivateData = 0;        /* Bytes to place into the private data buffer. */
    1242     uint32_t u32TargetLength = 0;      /* Bytes to place into the DMA buffer. */
    1243     uint32_t u32ProcessedLength = 0;   /* Bytes consumed from command buffer. */
    1244 
    1245     GALOG(("[%p] Command %p/%d, Dma %p/%d, Private %p/%d, MO %d, S %d, Phys 0x%RX64, AL %p/%d, PLLIn %p/%d, PLLOut %p/%d\n",
    1246            hContext,
    1247            pRender->pCommand, pRender->CommandLength,
    1248            pRender->pDmaBuffer, pRender->DmaSize,
    1249            pRender->pDmaBufferPrivateData, pRender->DmaBufferPrivateDataSize,
    1250            pRender->MultipassOffset, pRender->DmaBufferSegmentId, pRender->DmaBufferPhysicalAddress.QuadPart,
    1251            pRender->pAllocationList, pRender->AllocationListSize,
    1252            pRender->pPatchLocationListIn, pRender->PatchLocationListInSize,
    1253            pRender->pPatchLocationListOut, pRender->PatchLocationListOutSize
    1254          ));
    1255 
    1256     /* 32 bit handle at the start of the command buffer. */
    1257     if (pRender->MultipassOffset == 0)
    1258         pRender->MultipassOffset += sizeof(uint32_t);
    1259 
    1260     NTSTATUS Status = STATUS_SUCCESS;
    1261     __try
    1262     {
    1263         /* Calculate where the commands start. */
    1264         void const *pvSource = (uint8_t *)pRender->pCommand + pRender->MultipassOffset;
    1265         uint32_t cbSource = pRender->CommandLength - pRender->MultipassOffset;
    1266 
    1267         /* Generate DMA buffer from the supplied command buffer.
    1268          * Store the command buffer descriptor to pDmaBufferPrivateData.
    1269          *
    1270          * The display miniport driver must validate the command buffer.
    1271          *
    1272          * Copy commands to the pDmaBuffer.
    1273          * If a command uses a shared surface id, then replace the id with the original surface id.
    1274          */
    1275         if (pRender->DmaBufferPrivateDataSize >= sizeof(GARENDERDATA))
    1276         {
    1277             void *pvTarget          = pRender->pDmaBuffer;
    1278             uint32_t const cbTarget = pRender->DmaSize;
    1279             if (cbTarget > GA_DMA_MIN_SUBMIT_SIZE)
    1280             {
    1281                 Status = SvgaRenderCommands(pGaDevExt->hw.pSvga, pvTarget, cbTarget, pvSource, cbSource,
    1282                                             &u32TargetLength, &u32ProcessedLength);
    1283             }
    1284             else
    1285             {
    1286                 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1287             }
    1288 
    1289             GAFENCEOBJECT *pFO = NULL;
    1290             if (Status == STATUS_SUCCESS)
    1291             {
    1292                 /* Completed the command buffer. Check if there is a user mode fence. */
    1293                 uint32_t const u32FenceHandle = *(uint32_t *)pRender->pCommand;
    1294                 if (u32FenceHandle != 0)
    1295                 {
    1296                     /* Verify that the buffer handle is valid. */
    1297                     gaFenceObjectsLock(pGaDevExt);
    1298                     pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
    1299                     gaFenceObjectsUnlock(pGaDevExt);
    1300 
    1301                     if (!pFO) // Maybe silently ignore?
    1302                     {
    1303                         AssertFailed();
    1304                         Status = STATUS_INVALID_PARAMETER;
    1305                     }
    1306                 }
    1307 
    1308                 GALOG(("u32FenceHandle = %d, pFO = %p\n", u32FenceHandle, pFO));
    1309             }
    1310 
    1311             /* Fill RenderData description in any case, it will be ignored if the above code failed. */
    1312             pRenderData = (GARENDERDATA *)pRender->pDmaBufferPrivateData;
    1313             pRenderData->u32DataType  = GARENDERDATA_TYPE_RENDER;
    1314             pRenderData->cbData       = u32TargetLength;
    1315             pRenderData->pFenceObject = pFO;
    1316             pRenderData->pvDmaBuffer  = pRender->pDmaBuffer;
    1317             cbPrivateData = sizeof(GARENDERDATA);
    1318         }
    1319         else
    1320         {
    1321             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1322         }
    1323 
    1324         GALOG(("Status = 0x%x\n", Status));
    1325     }
    1326     __except (EXCEPTION_EXECUTE_HANDLER)
    1327     {
    1328         Status = STATUS_INVALID_PARAMETER;
    1329     }
    1330 
    1331     switch (Status)
    1332     {
    1333         case STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER:
    1334             pRender->MultipassOffset += u32ProcessedLength;
    1335             if (pRenderData == NULL)
    1336             {
    1337                 /* Not enough space in pDmaBufferPrivateData. */
    1338                 break;
    1339             }
    1340             RT_FALL_THRU();
    1341         case STATUS_SUCCESS:
    1342         {
    1343             Assert(pRenderData);
    1344             if (u32TargetLength == 0)
    1345             {
    1346                 /* Trigger command submission anyway by increasing pDmaBuffer */
    1347                 u32TargetLength = GA_DMA_MIN_SUBMIT_SIZE;
    1348 
    1349                 /* Update the DMA buffer description. */
    1350                 pRenderData->u32DataType  = GARENDERDATA_TYPE_FENCE;
    1351                 pRenderData->cbData       = u32TargetLength;
    1352                 /* pRenderData->pFenceObject stays */
    1353                 pRenderData->pvDmaBuffer  = NULL; /* Not used */
    1354             }
    1355             pRender->pDmaBuffer = (uint8_t *)pRender->pDmaBuffer + u32TargetLength;
    1356             pRender->pDmaBufferPrivateData = (uint8_t *)pRender->pDmaBufferPrivateData + cbPrivateData;
    1357         } break;
    1358         default: break;
    1359     }
    1360 
    1361     return Status;
    1362 }
    1363 
    1364 static NTSTATUS gaSoftwarePagingTransfer(PVBOXMP_DEVEXT pDevExt,
    1365                                          DXGKARG_BUILDPAGINGBUFFER *pBuildPagingBuffer)
    1366 {
    1367     RT_NOREF2(pDevExt, pBuildPagingBuffer);
    1368     /** @todo Implement.
    1369      * Do the SysMem <-> VRAM transfer in software, because
    1370      * the VMSVGA device does not have appropriate commands.
    1371      */
    1372     return STATUS_SUCCESS;
    1373 }
    1374 
    1375 NTSTATUS APIENTRY GaDxgkDdiBuildPagingBuffer(const HANDLE hAdapter,
    1376                                              DXGKARG_BUILDPAGINGBUFFER *pBuildPagingBuffer)
    1377 {
    1378     NTSTATUS Status = STATUS_SUCCESS;
    1379     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1380 
    1381     GALOG(("DmaBufferPrivateData %p/%d, DmaBuffer %p/%d\n",
    1382            pBuildPagingBuffer->pDmaBufferPrivateData,
    1383            pBuildPagingBuffer->DmaBufferPrivateDataSize,
    1384            pBuildPagingBuffer->pDmaBuffer,
    1385            pBuildPagingBuffer->DmaSize));
    1386 
    1387     /* Generate DMA buffer containing the commands.
    1388      * Store the command buffer descriptor pointer to pDmaBufferPrivateData.
    1389      */
    1390     GARENDERDATA *pRenderData = NULL;
    1391     uint32_t u32TargetLength = 0;
    1392     uint32_t cbPrivateData = 0;
    1393 
    1394     if (pBuildPagingBuffer->DmaBufferPrivateDataSize >= sizeof(GARENDERDATA))
    1395     {
    1396         // void *pvTarget          = pBuildPagingBuffer->pDmaBuffer;
    1397         const uint32_t cbTarget = pBuildPagingBuffer->DmaSize;
    1398         if (cbTarget > GA_DMA_MIN_SUBMIT_SIZE)
    1399         {
    1400             switch (pBuildPagingBuffer->Operation)
    1401             {
    1402                 case DXGK_OPERATION_TRANSFER:
    1403                 {
    1404                     GALOG(("DXGK_OPERATION_TRANSFER: %p: @0x%x, cb 0x%x; src: %d:%p; dst: %d:%p; flags 0x%x, off 0x%x\n",
    1405                            pBuildPagingBuffer->Transfer.hAllocation,
    1406                            pBuildPagingBuffer->Transfer.TransferOffset,
    1407                            pBuildPagingBuffer->Transfer.TransferSize,
    1408                            pBuildPagingBuffer->Transfer.Source.SegmentId,
    1409                            pBuildPagingBuffer->Transfer.Source.pMdl,
    1410                            pBuildPagingBuffer->Transfer.Destination.SegmentId,
    1411                            pBuildPagingBuffer->Transfer.Destination.pMdl,
    1412                            pBuildPagingBuffer->Transfer.Flags.Value,
    1413                            pBuildPagingBuffer->Transfer.MdlOffset));
    1414                     if (pBuildPagingBuffer->Transfer.Source.SegmentId == 0)
    1415                     {
    1416                         /* SysMem source. */
    1417                         if (pBuildPagingBuffer->Transfer.Destination.SegmentId == 1)
    1418                         {
    1419                             /* SysMem -> VRAM. */
    1420                             Status = gaSoftwarePagingTransfer(pDevExt, pBuildPagingBuffer);
    1421                             if (Status == STATUS_SUCCESS)
    1422                             {
    1423                                 /* Generate a NOP. */
    1424                                 Status = STATUS_NOT_SUPPORTED;
    1425                             }
    1426                         }
    1427                         else if (pBuildPagingBuffer->Transfer.Destination.SegmentId == 0)
    1428                         {
    1429                             /* SysMem -> SysMem, should not happen, bugcheck. */
    1430                             AssertFailed();
    1431                             Status = STATUS_INVALID_PARAMETER;
    1432                         }
    1433                         else
    1434                         {
    1435                             /* SysMem -> GPU surface. Our driver probably does not need it.
    1436                              * SVGA_3D_CMD_SURFACE_DMA(GMR -> Surface)?
    1437                              */
    1438                             AssertFailed();
    1439                             Status = STATUS_NOT_SUPPORTED;
    1440                         }
    1441                     }
    1442                     else if (pBuildPagingBuffer->Transfer.Source.SegmentId == 1)
    1443                     {
    1444                         /* VRAM source. */
    1445                         if (pBuildPagingBuffer->Transfer.Destination.SegmentId == 0)
    1446                         {
    1447                             /* VRAM -> SysMem. */
    1448                             Status = gaSoftwarePagingTransfer(pDevExt, pBuildPagingBuffer);
    1449                             if (Status == STATUS_SUCCESS)
    1450                             {
    1451                                 /* Generate a NOP. */
    1452                                 Status = STATUS_NOT_SUPPORTED;
    1453                             }
    1454                         }
    1455                         else if (pBuildPagingBuffer->Transfer.Destination.SegmentId == 1)
    1456                         {
    1457                             /* VRAM -> VRAM, should not happen, bugcheck. */
    1458                             AssertFailed();
    1459                             Status = STATUS_INVALID_PARAMETER;
    1460                         }
    1461                         else
    1462                         {
    1463                             /* VRAM -> GPU surface. Our driver probably does not need it.
    1464                              * SVGA_3D_CMD_SURFACE_DMA(SVGA_GMR_FRAMEBUFFER -> Surface)?
    1465                              */
    1466                             AssertFailed();
    1467                             Status = STATUS_NOT_SUPPORTED;
    1468                         }
    1469                     }
    1470                     else
    1471                     {
    1472                         /* GPU surface. Our driver probably does not need it.
    1473                          * SVGA_3D_CMD_SURFACE_DMA(Surface -> GMR)?
    1474                          */
    1475                         AssertFailed();
    1476                         Status = STATUS_NOT_SUPPORTED;
    1477                     }
    1478 
    1479                     /** @todo Ignore for now. */
    1480                     if (Status == STATUS_NOT_SUPPORTED)
    1481                     {
    1482                         /* NOP */
    1483                         Status = STATUS_SUCCESS;
    1484                     }
    1485                 } break;
    1486 
    1487                 case DXGK_OPERATION_FILL:
    1488                 {
    1489                     GALOG(("DXGK_OPERATION_FILL: %p: cb 0x%x, pattern 0x%x, %d:0x%08X\n",
    1490                            pBuildPagingBuffer->Fill.hAllocation,
    1491                            pBuildPagingBuffer->Fill.FillSize,
    1492                            pBuildPagingBuffer->Fill.FillPattern,
    1493                            pBuildPagingBuffer->Fill.Destination.SegmentId,
    1494                            pBuildPagingBuffer->Fill.Destination.SegmentAddress.LowPart));
    1495                     /* NOP */
    1496                 } break;
    1497 
    1498                 case DXGK_OPERATION_DISCARD_CONTENT:
    1499                 {
    1500                     GALOG(("DXGK_OPERATION_DISCARD_CONTENT: %p: flags 0x%x, %d:0x%08X\n",
    1501                            pBuildPagingBuffer->DiscardContent.hAllocation,
    1502                            pBuildPagingBuffer->DiscardContent.Flags,
    1503                            pBuildPagingBuffer->DiscardContent.SegmentId,
    1504                            pBuildPagingBuffer->DiscardContent.SegmentAddress.LowPart));
    1505                     /* NOP */
    1506                 } break;
    1507 
    1508                 default:
    1509                     AssertFailed();
    1510                     break;
    1511             }
    1512         }
    1513         else
    1514         {
    1515             Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1516         }
    1517 
    1518         /* Fill RenderData description in any case, it will be ignored if the above code failed. */
    1519         pRenderData = (GARENDERDATA *)pBuildPagingBuffer->pDmaBufferPrivateData;
    1520         pRenderData->u32DataType  = GARENDERDATA_TYPE_PAGING;
    1521         pRenderData->cbData       = u32TargetLength;
    1522         pRenderData->pFenceObject = NULL; /* Not a user request, so no user accessible fence object. */
    1523         pRenderData->pvDmaBuffer = pBuildPagingBuffer->pDmaBuffer;
    1524         cbPrivateData = sizeof(GARENDERDATA);
    1525     }
    1526     else
    1527     {
    1528         Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
    1529     }
    1530 
    1531     switch (Status)
    1532     {
    1533         case STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER:
    1534             AssertFailed(); /** @todo test */
    1535             if (pRenderData == NULL)
    1536             {
    1537                 /* Not enough space in pDmaBufferPrivateData. */
    1538                 break;
    1539             }
    1540             RT_FALL_THRU();
    1541         case STATUS_SUCCESS:
    1542         {
    1543             if (u32TargetLength)
    1544             {
    1545                 pBuildPagingBuffer->pDmaBuffer = (uint8_t *)pBuildPagingBuffer->pDmaBuffer + u32TargetLength;
    1546                 pBuildPagingBuffer->pDmaBufferPrivateData = (uint8_t *)pBuildPagingBuffer->pDmaBufferPrivateData + cbPrivateData;
    1547             }
    1548         } break;
    1549         default: break;
    1550     }
    1551 
    1552     return STATUS_SUCCESS;
    1553 }
    1554 
    1555 NTSTATUS APIENTRY GaDxgkDdiPatch(const HANDLE hAdapter, const DXGKARG_PATCH *pPatch)
    1556 {
    1557     RT_NOREF2(hAdapter, pPatch);
    1558     /* Nothing to do. */
    1559 
    1560     uint8_t *pu8DMABuffer = (uint8_t *)pPatch->pDmaBuffer + pPatch->DmaBufferSubmissionStartOffset;
    1561     UINT const cbDMABuffer = pPatch->DmaBufferSubmissionEndOffset - pPatch->DmaBufferSubmissionStartOffset;
    1562 
    1563     UINT i;
    1564     for (i = pPatch->PatchLocationListSubmissionStart; i < pPatch->PatchLocationListSubmissionLength; ++i)
    1565     {
    1566         D3DDDI_PATCHLOCATIONLIST const *pPatchList = &pPatch->pPatchLocationList[i];
    1567         Assert(pPatchList->AllocationIndex < pPatch->AllocationListSize);
    1568 
    1569         DXGK_ALLOCATIONLIST const *pAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
    1570         if (pAllocationList->SegmentId == 0)
    1571         {
    1572             WARN(("no segment id specified"));
    1573             continue;
    1574         }
    1575 
    1576         Assert(pAllocationList->SegmentId == 1);            /* CPU visible segment. */
    1577         Assert(pAllocationList->PhysicalAddress.HighPart == 0); /* The segment is less than 4GB. */
    1578         Assert(!(pAllocationList->PhysicalAddress.QuadPart & 0xfffUL)); /* <- just a check to ensure allocation offset does not go here */
    1579 
    1580         if (pPatchList->PatchOffset == ~0UL)
    1581         {
    1582             /* This is a dummy patch request, ignore. */
    1583             continue;
    1584         }
    1585 
    1586         if (pPatchList->PatchOffset >= cbDMABuffer) /// @todo A better condition.
    1587         {
    1588             WARN(("pPatchList->PatchOffset(%d) >= cbDMABuffer(%d)", pPatchList->PatchOffset, cbDMABuffer));
    1589             return STATUS_INVALID_PARAMETER;
    1590         }
    1591 
    1592         uint32_t *poffVRAM = (uint32_t *)(pu8DMABuffer + pPatchList->PatchOffset);
    1593         *poffVRAM = pAllocationList->PhysicalAddress.LowPart + pPatchList->AllocationOffset;
    1594     }
    1595 
    1596     return STATUS_SUCCESS;
    1597 }
    1598 
    1599 NTSTATUS APIENTRY GaDxgkDdiSubmitCommand(const HANDLE hAdapter, const DXGKARG_SUBMITCOMMAND *pSubmitCommand)
    1600 {
    1601     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1602     PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pSubmitCommand->hContext;
    1603     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1604 
    1605     GALOG(("pContext %p, fence %d\n", pContext, pSubmitCommand->SubmissionFenceId));
    1606 
    1607     const uint32_t cbPrivateData = pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset - pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset;
    1608     void *pvPrivateData = (uint8_t *)pSubmitCommand->pDmaBufferPrivateData + pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset;
    1609 
    1610     GALOG(("DmaBuffer (fence %d): End %d, Start %d\n",
    1611            pSubmitCommand->SubmissionFenceId, pSubmitCommand->DmaBufferSubmissionEndOffset,
    1612            pSubmitCommand->DmaBufferSubmissionStartOffset));
    1613     GALOG(("PrivateData (fence %d): End %d, Start %d, cb %d\n",
    1614            pSubmitCommand->SubmissionFenceId, pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset,
    1615            pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset, cbPrivateData));
    1616 
    1617     uint32_t cbDmaBufferSubmission = pSubmitCommand->DmaBufferSubmissionEndOffset - pSubmitCommand->DmaBufferSubmissionStartOffset;
    1618     uint32_t cDataBlocks = cbPrivateData / sizeof(GARENDERDATA);
    1619     AssertReturn(cDataBlocks, STATUS_INVALID_PARAMETER);
    1620 
    1621     GARENDERDATA *pRenderData = (GARENDERDATA *)pvPrivateData;
    1622     while (cDataBlocks--)
    1623     {
    1624         AssertReturn(cbDmaBufferSubmission >= pRenderData->cbData, STATUS_INVALID_PARAMETER);
    1625         cbDmaBufferSubmission -= pRenderData->cbData;
    1626 
    1627         void *pvDmaBuffer = NULL;
    1628         if (   pRenderData->u32DataType == GARENDERDATA_TYPE_RENDER
    1629             || pRenderData->u32DataType == GARENDERDATA_TYPE_FENCE)
    1630         {
    1631             if (pRenderData->u32DataType == GARENDERDATA_TYPE_RENDER)
    1632             {
    1633                 pvDmaBuffer = pRenderData->pvDmaBuffer;
    1634                 AssertPtrReturn(pvDmaBuffer, STATUS_INVALID_PARAMETER);
    1635             }
    1636 
    1637             GAFENCEOBJECT * const pFO = pRenderData->pFenceObject;
    1638             if (pFO) /* Can be NULL if the user mode driver does not need the fence for this buffer. */
    1639             {
    1640                 GALOG(("pFO = %p, u32FenceHandle = %d, Fence = %d\n",
    1641                        pFO, pFO->u32FenceHandle, pSubmitCommand->SubmissionFenceId));
    1642 
    1643                 gaFenceObjectsLock(pGaDevExt);
    1644 
    1645                 Assert(pFO->u32FenceState == GAFENCE_STATE_IDLE);
    1646                 pFO->u32SubmissionFenceId = pSubmitCommand->SubmissionFenceId;
    1647                 pFO->u32FenceState = GAFENCE_STATE_SUBMITTED;
    1648                 pFO->u64SubmittedTS = RTTimeNanoTS();
    1649 
    1650                 gaFenceObjectsUnlock(pGaDevExt);
    1651             }
    1652         }
    1653         else if (pRenderData->u32DataType == GARENDERDATA_TYPE_PRESENT)
    1654         {
    1655             pvDmaBuffer = pRenderData->pvDmaBuffer;
    1656             AssertPtrReturn(pvDmaBuffer, STATUS_INVALID_PARAMETER);
    1657         }
    1658         else if (pRenderData->u32DataType == GARENDERDATA_TYPE_PAGING)
    1659         {
    1660             pvDmaBuffer = pRenderData->pvDmaBuffer;
    1661             AssertPtrReturn(pvDmaBuffer, STATUS_INVALID_PARAMETER);
    1662         }
    1663         else
    1664         {
    1665             AssertFailedReturn(STATUS_INVALID_PARAMETER);
    1666         }
    1667 
    1668         if (pvDmaBuffer)
    1669         {
    1670             /* Copy DmaBuffer to Fifo. */
    1671             Assert(pSubmitCommand->DmaBufferSegmentId == 0);
    1672 
    1673             uint32_t const cbSubmit = pRenderData->cbData;
    1674 
    1675             void *pvCmd = SvgaFifoReserve(pGaDevExt->hw.pSvga, cbSubmit);
    1676             AssertPtrReturn(pvCmd, STATUS_INSUFFICIENT_RESOURCES);
    1677 
    1678             /* pvDmaBuffer is the actual address of the current data block.
    1679              * Therefore do not use pSubmitCommand->DmaBufferSubmissionStartOffset here.
    1680              */
    1681             memcpy(pvCmd, pvDmaBuffer, cbSubmit);
    1682             SvgaFifoCommit(pGaDevExt->hw.pSvga, cbSubmit);
    1683         }
    1684 
    1685         ++pRenderData;
    1686     }
    1687 
    1688     /* Submit the fence. */
    1689     SvgaFence(pGaDevExt->hw.pSvga, pSubmitCommand->SubmissionFenceId);
    1690 
    1691     ASMAtomicWriteU32(&pGaDevExt->u32LastSubmittedFenceId, pSubmitCommand->SubmissionFenceId);
    1692 
    1693     GALOG(("done %d\n", pSubmitCommand->SubmissionFenceId));
    1694     return STATUS_SUCCESS;
    1695 }
    1696 
    1697 BOOLEAN GaDxgkDdiInterruptRoutine(const PVOID MiniportDeviceContext,
    1698                                   ULONG MessageNumber)
    1699 {
    1700     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
    1701     RT_NOREF(MessageNumber);
    1702 
    1703     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1704     if (!pGaDevExt)
    1705     {
    1706         /* Device is not initialized yet. Not a Gallium interrupt, "return FALSE immediately". */
    1707         return FALSE;
    1708     }
    1709 
    1710     PVBOXWDDM_EXT_VMSVGA pSvga = pGaDevExt->hw.pSvga;
    1711     if (!pSvga)
    1712     {
    1713         /* Device is not initialized yet. Not a VMSVGA interrupt, "return FALSE immediately". */
    1714         return FALSE;
    1715     }
    1716 
    1717     const uint32_t u32IrqStatus = SVGAPortRead(pSvga, SVGA_IRQSTATUS_PORT);
    1718     if (!u32IrqStatus)
    1719     {
    1720         /* Not a VMSVGA interrupt, "return FALSE immediately". */
    1721         return FALSE;
    1722     }
    1723 
    1724     /* "Dismiss the interrupt on the adapter." */
    1725     SVGAPortWrite(pSvga, SVGA_IRQSTATUS_PORT, u32IrqStatus);
    1726     GALOG(("u32IrqStatus = 0x%08X\n", u32IrqStatus));
    1727 
    1728     /* Check what happened. */
    1729     if (u32IrqStatus & SVGA_IRQFLAG_ANY_FENCE)
    1730     {
    1731         /* A SVGA_CMD_FENCE command has been processed by the device. */
    1732         gaReportFence(pDevExt);
    1733     }
    1734 
    1735     GALOG(("leave\n"));
    1736     /* "Return TRUE as quickly as possible". */
    1737     return TRUE;
    1738 }
    1739 
    1740 VOID GaDxgkDdiDpcRoutine(const PVOID MiniportDeviceContext)
    1741 {
    1742     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
    1743     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1744     if (!pGaDevExt)
    1745     {
    1746         /* Device is not initialized yet. */
    1747         return;
    1748     }
    1749 
    1750     // pDevExt->u.primary.DxgkInterface.DxgkCbNotifyDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
    1751 
    1752     /* Scan fence objects and mark all with u32FenceId < u32LastCompletedFenceId as SIGNALED */
    1753     const uint32_t u32LastCompletedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedFenceId);
    1754 
    1755     gaFenceObjectsLock(pGaDevExt);
    1756 
    1757     GAFENCEOBJECT *pIter, *pNext;
    1758     RTListForEachSafe(&pGaDevExt->fenceObjects.list, pIter, pNext, GAFENCEOBJECT, node)
    1759     {
    1760         if (pIter->u32FenceState == GAFENCE_STATE_SUBMITTED)
    1761         {
    1762             if (gaFenceCmp(pIter->u32SubmissionFenceId, u32LastCompletedFenceId) <= 0)
    1763             {
    1764                 GALOG(("u32SubmissionFenceId %u -> SIGNALED %RU64 ns\n",
    1765                        pIter->u32SubmissionFenceId, RTTimeNanoTS() - pIter->u64SubmittedTS));
    1766 
    1767                 ASMAtomicWriteU32(&pGaDevExt->u32LastCompletedSeqNo, pIter->u32SeqNo);
    1768                 pIter->u32FenceState = GAFENCE_STATE_SIGNALED;
    1769                 if (RT_BOOL(pIter->fu32FenceFlags & GAFENCE_F_WAITED))
    1770                 {
    1771                     KeSetEvent(&pIter->event, 0, FALSE);
    1772                 }
    1773 
    1774                 gaFenceUnrefLocked(pGaDevExt, pIter);
    1775             }
    1776         }
    1777     }
    1778 
    1779     gaFenceObjectsUnlock(pGaDevExt);
    1780 }
    1781 
    1782 typedef struct GAPREEMPTCOMMANDCBCTX
    1783 {
    1784     PVBOXMP_DEVEXT pDevExt;
    1785     UINT uPreemptionFenceId;
    1786     UINT uLastCompletedFenceId;
    1787 } GAPREEMPTCOMMANDCBCTX;
    1788 
    1789 static BOOLEAN gaPreemptCommandCb(PVOID Context)
    1790 {
    1791     GAPREEMPTCOMMANDCBCTX *pCtx = (GAPREEMPTCOMMANDCBCTX *)Context;
    1792     dxgkNotifyDma(&pCtx->pDevExt->u.primary.DxgkInterface, DXGK_INTERRUPT_DMA_PREEMPTED,
    1793                   0, pCtx->uPreemptionFenceId, pCtx->uLastCompletedFenceId);
    1794     return TRUE;
    1795 }
    1796 
    1797 NTSTATUS APIENTRY GaDxgkDdiPreemptCommand(const HANDLE hAdapter,
    1798                                           const DXGKARG_PREEMPTCOMMAND *pPreemptCommand)
    1799 {
    1800     NTSTATUS Status;
    1801 
    1802     GALOG(("hAdapter %p, fence %d\n", hAdapter, pPreemptCommand->PreemptionFenceId));
    1803 
    1804     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1805     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1806     if (!pGaDevExt)
    1807     {
    1808         /* Device is not initialized yet. */
    1809         return STATUS_SUCCESS;
    1810     }
    1811 
    1812     /* We can not safely remove submitted data from FIFO, so just let the host process all submitted commands.
    1813      */
    1814     const uint32_t u32LastCompletedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedFenceId);
    1815     const uint32_t u32LastSubmittedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastSubmittedFenceId);
    1816     if (u32LastCompletedFenceId == u32LastSubmittedFenceId)
    1817     {
    1818         GAPREEMPTCOMMANDCBCTX Ctx;
    1819         Ctx.pDevExt = pDevExt;
    1820         Ctx.uPreemptionFenceId = pPreemptCommand->PreemptionFenceId;
    1821         Ctx.uLastCompletedFenceId = u32LastCompletedFenceId;
    1822 
    1823         DXGKRNL_INTERFACE *pDxgkInterface = &pDevExt->u.primary.DxgkInterface;
    1824         BOOLEAN bReturnValue = FALSE;
    1825         Status = pDxgkInterface->DxgkCbSynchronizeExecution(pDxgkInterface->DeviceHandle,
    1826                                                             gaPreemptCommandCb, &Ctx, 0, &bReturnValue);
    1827         Assert(bReturnValue);
    1828     }
    1829     else
    1830     {
    1831         /* Submit the fence. */
    1832         Assert(pGaDevExt->u32PreemptionFenceId == 0);
    1833         ASMAtomicWriteU32(&pGaDevExt->u32PreemptionFenceId, pPreemptCommand->PreemptionFenceId);
    1834         Status = SvgaFence(pGaDevExt->hw.pSvga, pPreemptCommand->PreemptionFenceId);
    1835     }
    1836 
    1837     return Status;
    1838 }
    1839 
    1840 static BOOLEAN gaQueryCurrentFenceCb(PVOID Context)
    1841 {
    1842     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)Context;
    1843     gaReportFence(pDevExt);
    1844     return TRUE;
    1845 }
    1846 
    1847 NTSTATUS APIENTRY GaDxgkDdiQueryCurrentFence(const HANDLE hAdapter,
    1848                                              DXGKARG_QUERYCURRENTFENCE *pCurrentFence)
    1849 {
    1850     NTSTATUS Status;
    1851 
    1852     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1853     VBOXWDDM_EXT_GA *pGaDevExt = pDevExt->pGa;
    1854     if (!pGaDevExt)
    1855     {
    1856         /* Device is not initialized yet. */
    1857         return STATUS_SUCCESS;
    1858     }
    1859 
    1860     DXGKRNL_INTERFACE *pDxgkInterface = &pDevExt->u.primary.DxgkInterface;
    1861     LARGE_INTEGER DelayInterval;
    1862     DelayInterval.QuadPart = -10LL * 1000LL * 1000LL;
    1863     uint32_t u32LastCompletedFenceId = 0;
    1864 
    1865     /* Wait until the host processes all submitted buffers to allow delays on the host (debug, etc). */
    1866     for (;;)
    1867     {
    1868         BOOLEAN bReturnValue = FALSE;
    1869         Status = pDxgkInterface->DxgkCbSynchronizeExecution(pDxgkInterface->DeviceHandle,
    1870                                                             gaQueryCurrentFenceCb, pDevExt, 0, &bReturnValue);
    1871         Assert(bReturnValue);
    1872         if (Status != STATUS_SUCCESS)
    1873         {
    1874             break;
    1875         }
    1876 
    1877         u32LastCompletedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedFenceId);
    1878         uint32_t const u32LastSubmittedFenceId = ASMAtomicReadU32(&pGaDevExt->u32LastSubmittedFenceId);
    1879         if (u32LastCompletedFenceId == u32LastSubmittedFenceId)
    1880         {
    1881             break;
    1882         }
    1883 
    1884         GALOG(("hAdapter %p, LastCompletedFenceId %d, LastSubmittedFenceId %d...\n", hAdapter, u32LastCompletedFenceId, u32LastSubmittedFenceId));
    1885 
    1886         KeDelayExecutionThread(KernelMode, FALSE, &DelayInterval);
    1887     }
    1888 
    1889     if (Status == STATUS_SUCCESS)
    1890     {
    1891         pCurrentFence->CurrentFence = u32LastCompletedFenceId;
    1892     }
    1893 
    1894     GALOG(("hAdapter %p, CurrentFence %d, Status 0x%x\n", hAdapter, pCurrentFence->CurrentFence, Status));
    1895 
    1896     return Status;
    1897 }
    1898 
    1899 NTSTATUS APIENTRY GaDxgkDdiEscape(const HANDLE hAdapter,
    1900                                   const DXGKARG_ESCAPE *pEscape)
    1901 {
    1902     if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE))
    1903     {
    1904         AssertFailed();
    1905         return STATUS_INVALID_PARAMETER;
    1906     }
    1907 
    1908     NTSTATUS Status = STATUS_NOT_SUPPORTED;
    1909     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    1910     PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)pEscape->hDevice;
    1911     PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
    1912     const VBOXDISPIFESCAPE *pEscapeHdr = (VBOXDISPIFESCAPE *)pEscape->pPrivateDriverData;
    1913     switch (pEscapeHdr->escapeCode)
    1914     {
    1915         case VBOXESC_GAGETCID:
    1916         {
    1917             if (!pContext)
    1918             {
    1919                 Status = STATUS_INVALID_PARAMETER;
    1920                 break;
    1921             }
    1922 
    1923             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAGETCID))
    1924             {
    1925                 Status = STATUS_INVALID_PARAMETER;
    1926                 break;
    1927             }
    1928 
    1929             VBOXDISPIFESCAPE_GAGETCID *pGaGetCid = (VBOXDISPIFESCAPE_GAGETCID *)pEscapeHdr;
    1930             pGaGetCid->u32Cid = pContext->u32Cid;
    1931             Status = STATUS_SUCCESS;
    1932             break;
    1933         }
    1934         case VBOXESC_GAREGION:
    1935         {
    1936             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAREGION))
    1937             {
    1938                 Status = STATUS_INVALID_PARAMETER;
    1939                 break;
    1940             }
    1941 
    1942             VBOXDISPIFESCAPE_GAREGION *pGaRegion = (VBOXDISPIFESCAPE_GAREGION *)pEscapeHdr;
    1943             if (pGaRegion->u32Command == GA_REGION_CMD_CREATE)
    1944             {
    1945                 Status = SvgaRegionCreate(pDevExt->pGa->hw.pSvga, pDevice, pGaRegion->u32NumPages, &pGaRegion->u32GmrId, &pGaRegion->u64UserAddress);
    1946             }
    1947             else if (pGaRegion->u32Command == GA_REGION_CMD_DESTROY)
    1948             {
    1949                 Status = SvgaRegionDestroy(pDevExt->pGa->hw.pSvga, pGaRegion->u32GmrId);
    1950             }
    1951             else
    1952             {
    1953                 Status = STATUS_INVALID_PARAMETER;
    1954             }
    1955         } break;
    1956         case VBOXESC_GAPRESENT:
    1957         {
    1958             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAPRESENT))
    1959             {
    1960                 Status = STATUS_INVALID_PARAMETER;
    1961                 break;
    1962             }
    1963 
    1964             VBOXDISPIFESCAPE_GAPRESENT *pGaPresent = (VBOXDISPIFESCAPE_GAPRESENT *)pEscapeHdr;
    1965             /** @todo This always writes to the start of VRAM. This is a debug function
    1966              * and is not used for normal operations anymore.
    1967              */
    1968             Status = gaPresent(pDevExt->pGa, pGaPresent->u32Sid, pGaPresent->u32Width, pGaPresent->u32Height, 0);
    1969             break;
    1970         }
    1971         case VBOXESC_GASURFACEDEFINE:
    1972         {
    1973             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GASURFACEDEFINE))
    1974             {
    1975                 Status = STATUS_INVALID_PARAMETER;
    1976                 break;
    1977             }
    1978 
    1979             VBOXDISPIFESCAPE_GASURFACEDEFINE *pGaSurfaceDefine = (VBOXDISPIFESCAPE_GASURFACEDEFINE *)pEscapeHdr;
    1980             if (pEscape->PrivateDriverDataSize - sizeof(VBOXDISPIFESCAPE_GASURFACEDEFINE) < pGaSurfaceDefine->cbReq)
    1981             {
    1982                 Status = STATUS_INVALID_PARAMETER;
    1983                 break;
    1984             }
    1985 
    1986             GASURFCREATE *pCreateParms = (GASURFCREATE *)&pGaSurfaceDefine[1];
    1987             GASURFSIZE *paSizes = (GASURFSIZE *)&pCreateParms[1];
    1988 
    1989             /// @todo verify the data
    1990             Status = gaSurfaceDefine(pDevExt->pGa, pCreateParms, paSizes, pGaSurfaceDefine->cSizes, &pGaSurfaceDefine->u32Sid);
    1991             break;
    1992         }
    1993         case VBOXESC_GASURFACEDESTROY:
    1994         {
    1995             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GASURFACEDESTROY))
    1996             {
    1997                 Status = STATUS_INVALID_PARAMETER;
    1998                 break;
    1999             }
    2000 
    2001             VBOXDISPIFESCAPE_GASURFACEDESTROY *pGaSurfaceDestroy = (VBOXDISPIFESCAPE_GASURFACEDESTROY *)pEscapeHdr;
    2002             Status = gaSurfaceDestroy(pDevExt->pGa, pGaSurfaceDestroy->u32Sid);
    2003             break;
    2004         }
    2005         case VBOXESC_GASHAREDSID:
    2006         {
    2007             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GASHAREDSID))
    2008             {
    2009                 Status = STATUS_INVALID_PARAMETER;
    2010                 break;
    2011             }
    2012 
    2013             VBOXDISPIFESCAPE_GASHAREDSID *pGaSharedSid = (VBOXDISPIFESCAPE_GASHAREDSID *)pEscapeHdr;
    2014             if (pGaSharedSid->u32SharedSid == ~0)
    2015             {
    2016                 Status = gaSharedSidRemove(pDevExt->pGa, pGaSharedSid->u32Sid);
    2017             }
    2018             else
    2019             {
    2020                 Status = gaSharedSidInsert(pDevExt->pGa, pGaSharedSid->u32Sid, pGaSharedSid->u32SharedSid);
    2021             }
    2022             break;
    2023         }
    2024         case VBOXESC_GAFENCECREATE:
    2025         {
    2026             if (!pDevice)
    2027             {
    2028                 Status = STATUS_INVALID_PARAMETER;
    2029                 break;
    2030             }
    2031 
    2032             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAFENCECREATE))
    2033             {
    2034                 Status = STATUS_INVALID_PARAMETER;
    2035                 break;
    2036             }
    2037 
    2038             VBOXDISPIFESCAPE_GAFENCECREATE *pFenceCreate = (VBOXDISPIFESCAPE_GAFENCECREATE *)pEscapeHdr;
    2039             Status = GaFenceCreate(pDevExt->pGa, pDevice, &pFenceCreate->u32FenceHandle);
    2040             break;
    2041         }
    2042         case VBOXESC_GAFENCEQUERY:
    2043         {
    2044             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAFENCEQUERY))
    2045             {
    2046                 Status = STATUS_INVALID_PARAMETER;
    2047                 break;
    2048             }
    2049 
    2050             VBOXDISPIFESCAPE_GAFENCEQUERY *pFenceQuery = (VBOXDISPIFESCAPE_GAFENCEQUERY *)pEscapeHdr;
    2051             Status = GaFenceQuery(pDevExt->pGa, pFenceQuery->u32FenceHandle,
    2052                                   &pFenceQuery->u32SubmittedSeqNo, &pFenceQuery->u32ProcessedSeqNo,
    2053                                   &pFenceQuery->u32FenceStatus);
    2054             break;
    2055         }
    2056         case VBOXESC_GAFENCEWAIT:
    2057         {
    2058             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAFENCEWAIT))
    2059             {
    2060                 Status = STATUS_INVALID_PARAMETER;
    2061                 break;
    2062             }
    2063 
    2064             VBOXDISPIFESCAPE_GAFENCEWAIT *pFenceWait = (VBOXDISPIFESCAPE_GAFENCEWAIT *)pEscapeHdr;
    2065             Status = GaFenceWait(pDevExt->pGa, pFenceWait->u32FenceHandle, pFenceWait->u32TimeoutUS);
    2066             break;
    2067         }
    2068         case VBOXESC_GAFENCEUNREF:
    2069         {
    2070             if (pEscape->PrivateDriverDataSize < sizeof(VBOXDISPIFESCAPE_GAFENCEUNREF))
    2071             {
    2072                 Status = STATUS_INVALID_PARAMETER;
    2073                 break;
    2074             }
    2075 
    2076             VBOXDISPIFESCAPE_GAFENCEUNREF *pFenceUnref = (VBOXDISPIFESCAPE_GAFENCEUNREF *)pEscapeHdr;
    2077             Status = GaFenceUnref(pDevExt->pGa, pFenceUnref->u32FenceHandle);
    2078             break;
    2079         }
    2080         default:
    2081             break;
    2082     }
    2083 
    2084     return Status;
    2085 }
    2086 
    2087 DECLINLINE(VBOXVIDEOOFFSET) vboxWddmAddrVRAMOffset(VBOXWDDM_ADDR const *pAddr)
    2088 {
    2089     return (pAddr->offVram != VBOXVIDEOOFFSET_VOID && pAddr->SegmentId) ?
    2090                 (pAddr->SegmentId == 1 ? pAddr->offVram : 0) :
    2091                 VBOXVIDEOOFFSET_VOID;
    2092 }
    2093 
    2094 static void vboxWddmRectCopy(void *pvDst, uint32_t cbDstBytesPerPixel, uint32_t cbDstPitch,
    2095                              void const *pvSrc, uint32_t cbSrcBytesPerPixel, uint32_t cbSrcPitch,
    2096                              RECT const *pRect)
    2097 {
    2098     uint8_t *pu8Dst = (uint8_t *)pvDst;
    2099     pu8Dst += pRect->top * cbDstPitch + pRect->left * cbDstBytesPerPixel;
    2100 
    2101     uint8_t const *pu8Src = (uint8_t *)pvSrc;
    2102     pu8Src += pRect->top * cbSrcPitch + pRect->left * cbSrcBytesPerPixel;
    2103 
    2104     uint32_t const cbLine = (pRect->right - pRect->left) * cbDstBytesPerPixel;
    2105     for (INT y = pRect->top; y < pRect->bottom; ++y)
    2106     {
    2107         memcpy(pu8Dst, pu8Src, cbLine);
    2108         pu8Dst += cbDstPitch;
    2109         pu8Src += cbSrcPitch;
    2110     }
    2111 }
    2112 
    2113 static NTSTATUS gaSourceBlitToScreen(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_SOURCE *pSource, RECT const *pRect)
    2114 {
    2115     NTSTATUS Status = STATUS_SUCCESS;
    2116     PVBOXWDDM_EXT_VMSVGA pSvga = pDevExt->pGa->hw.pSvga;
    2117 
    2118     VBOXWDDM_TARGET_ITER Iter;
    2119     VBoxVidPnStTIterInit(pSource, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, &Iter);
    2120     for (PVBOXWDDM_TARGET pTarget = VBoxVidPnStTIterNext(&Iter);
    2121          pTarget;
    2122          pTarget = VBoxVidPnStTIterNext(&Iter))
    2123     {
    2124         Status = SvgaBlitGMRFBToScreen(pSvga,
    2125                                        pTarget->u32Id,
    2126                                        pRect->left,
    2127                                        pRect->top,
    2128                                        pRect);
    2129         AssertBreak(Status == STATUS_SUCCESS);
    2130     }
    2131 
    2132     return Status;
    2133 }
    2134 
    2135 NTSTATUS APIENTRY GaDxgkDdiPresentDisplayOnly(const HANDLE hAdapter,
    2136                                               const DXGKARG_PRESENT_DISPLAYONLY *pPresentDisplayOnly)
    2137 {
    2138     PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
    2139 
    2140     LOG(("VidPnSourceId %d, pSource %p, BytesPerPixel %d, Pitch %d, Flags 0x%x, NumMoves %d, NumDirtyRects %d, pfn %p\n",
    2141          pPresentDisplayOnly->VidPnSourceId,
    2142          pPresentDisplayOnly->pSource,
    2143          pPresentDisplayOnly->BytesPerPixel,
    2144          pPresentDisplayOnly->Pitch,
    2145          pPresentDisplayOnly->Flags.Value,
    2146          pPresentDisplayOnly->NumMoves,
    2147          pPresentDisplayOnly->NumDirtyRects,
    2148          pPresentDisplayOnly->pDirtyRect,
    2149          pPresentDisplayOnly->pfnPresentDisplayOnlyProgress));
    2150 
    2151     /*
    2152      * Copy the image to the corresponding VidPn source allocation.
    2153      */
    2154     PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pPresentDisplayOnly->VidPnSourceId];
    2155     AssertReturn(pSource->AllocData.Addr.SegmentId == 1, STATUS_SUCCESS); /* Ignore such VidPn sources. */
    2156 
    2157     VBOXVIDEOOFFSET const offVRAM = vboxWddmAddrVRAMOffset(&pSource->AllocData.Addr);
    2158     AssertReturn(offVRAM != VBOXVIDEOOFFSET_VOID, STATUS_SUCCESS); /* Ignore such VidPn sources. */
    2159 
    2160     for (ULONG i = 0; i < pPresentDisplayOnly->NumMoves; ++i)
    2161     {
    2162         RECT *pRect = &pPresentDisplayOnly->pMoves[i].DestRect;
    2163         vboxWddmRectCopy(pDevExt->pvVisibleVram + offVRAM,    // dst pointer
    2164                          pSource->AllocData.SurfDesc.bpp / 8, // dst bytes per pixel
    2165                          pSource->AllocData.SurfDesc.pitch,   // dst pitch
    2166                          pPresentDisplayOnly->pSource,        // src pointer
    2167                          pPresentDisplayOnly->BytesPerPixel,  // src bytes per pixel
    2168                          pPresentDisplayOnly->Pitch,          // src pitch
    2169                          pRect);
    2170     }
    2171 
    2172     for (ULONG i = 0; i < pPresentDisplayOnly->NumDirtyRects; ++i)
    2173     {
    2174         RECT *pRect = &pPresentDisplayOnly->pDirtyRect[i];
    2175         if (pRect->left >= pRect->right || pRect->top >= pRect->bottom)
    2176         {
    2177             continue;
    2178         }
    2179 
    2180         vboxWddmRectCopy(pDevExt->pvVisibleVram + offVRAM,    // dst pointer
    2181                          pSource->AllocData.SurfDesc.bpp / 8, // dst bytes per pixel
    2182                          pSource->AllocData.SurfDesc.pitch,   // dst pitch
    2183                          pPresentDisplayOnly->pSource,        // src pointer
    2184                          pPresentDisplayOnly->BytesPerPixel,  // src bytes per pixel
    2185                          pPresentDisplayOnly->Pitch,          // src pitch
    2186                          pRect);
    2187     }
    2188 
    2189     NTSTATUS Status = STATUS_SUCCESS;
    2190     if (pSource->bVisible) /// @todo Does/should this have any effect?
    2191     {
    2192         PVBOXWDDM_EXT_VMSVGA pSvga = pDevExt->pGa->hw.pSvga;
    2193         Status = SvgaDefineGMRFB(pSvga, (uint32_t)offVRAM, pSource->AllocData.SurfDesc.pitch, false);
    2194         if (Status == STATUS_SUCCESS)
    2195         {
    2196             for (ULONG i = 0; i < pPresentDisplayOnly->NumMoves; ++i)
    2197             {
    2198                 RECT *pRect = &pPresentDisplayOnly->pMoves[i].DestRect;
    2199                 Status = gaSourceBlitToScreen(pDevExt, pSource, pRect);
    2200                 AssertBreak(Status == STATUS_SUCCESS);
    2201             }
    2202         }
    2203 
    2204         if (Status == STATUS_SUCCESS)
    2205         {
    2206             for (ULONG i = 0; i < pPresentDisplayOnly->NumDirtyRects; ++i)
    2207             {
    2208                 RECT *pRect = &pPresentDisplayOnly->pDirtyRect[i];
    2209                 Status = gaSourceBlitToScreen(pDevExt, pSource, pRect);
    2210                 AssertBreak(Status == STATUS_SUCCESS);
    2211             }
    2212         }
    2213     }
    2214 
    2215     return Status;
    2216 }
    2217 
    2218 NTSTATUS GaVidPnSourceReport(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_SOURCE *pSource)
    2219 {
    2220     NTSTATUS Status = STATUS_SUCCESS;
    2221 
    2222     VBOXVIDEOOFFSET offVRAM = vboxWddmAddrVRAMOffset(&pSource->AllocData.Addr);
    2223     if (offVRAM == VBOXVIDEOOFFSET_VOID)
    2224         return STATUS_SUCCESS; /* Ignore such VidPn sources. */
    2225 
    2226     VBOXWDDM_TARGET_ITER Iter;
    2227     VBoxVidPnStTIterInit(pSource, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, &Iter);
    2228     for (PVBOXWDDM_TARGET pTarget = VBoxVidPnStTIterNext(&Iter);
    2229          pTarget;
    2230          pTarget = VBoxVidPnStTIterNext(&Iter))
    2231     {
    2232         Status = GaScreenDefine(pDevExt->pGa,
    2233                                 (uint32_t)offVRAM,
    2234                                 pTarget->u32Id,
    2235                                 pSource->VScreenPos.x, pSource->VScreenPos.y,
    2236                                 pSource->AllocData.SurfDesc.width, pSource->AllocData.SurfDesc.height,
    2237                                 RT_BOOL(pSource->bBlankedByPowerOff));
    2238         AssertBreak(Status == STATUS_SUCCESS);
    2239     }
    2240 
    2241     return Status;
    2242 }
    2243 
    2244 NTSTATUS GaVidPnSourceCheckPos(PVBOXMP_DEVEXT pDevExt, UINT iSource)
    2245 {
    2246     POINT Pos = {0};
    2247     NTSTATUS Status = vboxWddmDisplaySettingsQueryPos(pDevExt, iSource, &Pos);
    2248     if (NT_SUCCESS(Status))
    2249     {
    2250         PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[iSource];
    2251         if (memcmp(&pSource->VScreenPos, &Pos, sizeof(Pos)))
    2252         {
    2253             pSource->VScreenPos = Pos;
    2254             Status = GaVidPnSourceReport(pDevExt, pSource);
    2255         }
    2256     }
    2257     return Status;
    2258 }
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPGaWddm.cpp

    r76790 r76884  
    1818#include "VBoxMPGaWddm.h"
    1919#include "../VBoxMPVidPn.h"
     20#include "VBoxMPGaExt.h"
    2021
    2122#include "Svga.h"
     
    2627#include <iprt/time.h>
    2728
    28 volatile uint32_t g_fu32GaLogControl =
    29 #ifdef DEBUG
    30     1 /* Enable LogRels */
    31 #else
    32     0 /* Disable LogRels, but they can be enabled if necessary. */
    33 #endif
    34 ;
    35 
    36 
    37 #define VBOXWDDM_GA_MAX_FENCE_OBJECTS 4096
    38 
    39 /* Gallium related device extension. */
    40 typedef struct VBOXWDDM_EXT_GA
    41 {
    42     union
    43     {
    44         /* Pointers to HW specific structs. */
    45         PVBOXWDDM_EXT_VMSVGA pSvga;
    46         void *pv;
    47     } hw;
    48 
    49     volatile uint32_t u32LastSubmittedFenceId; /* Updated in GaDxgkSubmitCommand. */
    50     volatile uint32_t u32LastCompletedFenceId; /* Updated in ISR. */
    51     volatile uint32_t u32PreemptionFenceId; /* Updated in GaDxgkDdiPreemptCommand. */
    52     volatile uint32_t u32LastCompletedSeqNo; /* Updated in DPC routine. */
    53 
    54     struct
    55     {
    56         /* Generation of SeqNo's. */
    57         volatile uint32_t u32SeqNoSource;
    58         /* Lock for accessing fence objects. Spin lock because it is used in DPC routine too. */
    59         KIRQL OldIrql;
    60         KSPIN_LOCK SpinLock;
    61         /* List of all fence objects. */
    62         RTLISTANCHOR list;
    63         /** Bitmap of used fence handles. Bit 0 - fence handle 0, etc. */
    64         uint32_t au32HandleBits[(VBOXWDDM_GA_MAX_FENCE_OBJECTS + 31) / 32];
    65     } fenceObjects;
    66 } VBOXWDDM_EXT_GA;
    67 
    68 /* Fence object (FO). */
    69 typedef struct GAFENCEOBJECT
    70 {
    71     volatile uint32_t cRefs;    /* By UM driver, by waiter, during submission. */
    72     uint32_t u32FenceHandle;    /* Unique identifier, used for communications with UM driver. */
    73     uint32_t u32FenceState;     /* GAFENCE_STATE_* */
    74     uint32_t fu32FenceFlags;    /* GAFENCE_F_* */
    75     uint32_t u32SubmissionFenceId; /* DXGK fence id. */
    76     uint32_t u32SeqNo;          /* Gallium Sequence Number, generated by the miniport. */
    77     PVBOXWDDM_DEVICE pDevice;   /* Device the fence is associated with. */
    78     KEVENT event;               /* Allows to wait for the fence completion. */
    79     RTLISTNODE node;            /* For the per adapter list of fence objects. */
    80     uint64_t u64SubmittedTS;    /* Nanoseconds timestamp when the corresponding buffer was submitted. */
    81 } GAFENCEOBJECT;
    82 
    83 #define GAFENCE_STATE_IDLE      0
    84 #define GAFENCE_STATE_SUBMITTED 1
    85 #define GAFENCE_STATE_SIGNALED  2
    86 
    87 #define GAFENCE_F_WAITED        0x1 /* KEVENT is initialized and there is(are) waiter(s). */
    88 
    89 
    90 /*
    91  * Helpers.
    92  */
    93 
    94 void *GaMemAlloc(uint32_t cbSize)
    95 {
    96     return ExAllocatePoolWithTag(NonPagedPool, cbSize, 'AGBV');
    97 }
    98 
    99 void *GaMemAllocZero(uint32_t cbSize)
    100 {
    101     void *pvMem = GaMemAlloc(cbSize);
    102     if (pvMem)
    103         memset(pvMem, 0, cbSize);
    104     return pvMem;
    105 }
    106 
    107 void GaMemFree(void *pvMem)
    108 {
    109     ExFreePool(pvMem);
    110 }
    111 
    112 NTSTATUS GaIdAlloc(uint32_t *pu32Bits,
    113                    uint32_t cbBits,
    114                    uint32_t u32Limit,
    115                    uint32_t *pu32Id)
    116 {
    117     /* Find the first zero bit. */
    118     const int32_t i32Id = ASMBitFirstClear(pu32Bits, cbBits * 8);
    119     if (0 <= i32Id && i32Id < (int32_t)u32Limit)
    120     {
    121         ASMBitSet(pu32Bits, i32Id);
    122         *pu32Id = (uint32_t)i32Id;
    123         return STATUS_SUCCESS;
    124     }
    125 
    126     return STATUS_INSUFFICIENT_RESOURCES;
    127 }
    128 
    129 NTSTATUS GaIdFree(uint32_t *pu32Bits,
    130                   uint32_t cbBits,
    131                   uint32_t u32Limit,
    132                   uint32_t u32Id)
    133 {
    134     AssertReturn(u32Limit <= cbBits * 8, STATUS_INVALID_PARAMETER);
    135     AssertReturn(u32Id < u32Limit, STATUS_INVALID_PARAMETER);
    136 
    137     /* Clear the corresponding bit. */
    138     ASMBitClear(pu32Bits, (int32_t)u32Id);
    139 
    140     return STATUS_SUCCESS;
    141 }
    142 
    143 
    144 DECLINLINE(void) gaFenceObjectsLock(VBOXWDDM_EXT_GA *pGaDevExt)
    145 {
    146     KeAcquireSpinLock(&pGaDevExt->fenceObjects.SpinLock, &pGaDevExt->fenceObjects.OldIrql);
    147 }
    148 
    149 DECLINLINE(void) gaFenceObjectsUnlock(VBOXWDDM_EXT_GA *pGaDevExt)
    150 {
    151     KeReleaseSpinLock(&pGaDevExt->fenceObjects.SpinLock, pGaDevExt->fenceObjects.OldIrql);
    152 }
    153 
    154 static void gaFenceObjectsDestroy(VBOXWDDM_EXT_GA *pGaDevExt,
    155                                   PVBOXWDDM_DEVICE pDevice)
    156 {
    157     RTLISTANCHOR list;
    158     RTListInit(&list);
    159 
    160     gaFenceObjectsLock(pGaDevExt);
    161 
    162     GAFENCEOBJECT *pIter, *pNext;
    163     RTListForEachSafe(&pGaDevExt->fenceObjects.list, pIter, pNext, GAFENCEOBJECT, node)
    164     {
    165         if (   pDevice == NULL
    166             || pIter->pDevice == pDevice)
    167         {
    168             /* Remove from list, add to the local list. */
    169             RTListNodeRemove(&pIter->node);
    170             GaIdFree(pGaDevExt->fenceObjects.au32HandleBits, sizeof(pGaDevExt->fenceObjects.au32HandleBits),
    171                      VBOXWDDM_GA_MAX_FENCE_OBJECTS, pIter->u32FenceHandle);
    172             RTListAppend(&list, &pIter->node);
    173         }
    174     }
    175 
    176     gaFenceObjectsUnlock(pGaDevExt);
    177 
    178     /* Deallocate list. */
    179     RTListForEachSafe(&list, pIter, pNext, GAFENCEOBJECT, node)
    180     {
    181         GALOG(("Deallocate u32FenceHandle = %d for %p\n", pIter->u32FenceHandle, pDevice));
    182         RTListNodeRemove(&pIter->node);
    183         GaMemFree(pIter);
    184     }
    185 }
    186 
    187 static void gaFenceDelete(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
    188 {
    189     GALOG(("u32FenceHandle = %d, pFO %p\n", pFO->u32FenceHandle, pFO));
    190 
    191     gaFenceObjectsLock(pGaDevExt);
    192 
    193     RTListNodeRemove(&pFO->node);
    194     GaIdFree(pGaDevExt->fenceObjects.au32HandleBits, sizeof(pGaDevExt->fenceObjects.au32HandleBits),
    195              VBOXWDDM_GA_MAX_FENCE_OBJECTS, pFO->u32FenceHandle);
    196 
    197     gaFenceObjectsUnlock(pGaDevExt);
    198 
    199     /// @todo Pool of fence objects to avoid memory allocations.
    200     GaMemFree(pFO);
    201 }
    202 
    203 static void gaFenceDeleteLocked(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
    204 {
    205     GALOG(("u32FenceHandle = %d, pFO %p\n", pFO->u32FenceHandle, pFO));
    206 
    207     RTListNodeRemove(&pFO->node);
    208     GaIdFree(pGaDevExt->fenceObjects.au32HandleBits, sizeof(pGaDevExt->fenceObjects.au32HandleBits),
    209              VBOXWDDM_GA_MAX_FENCE_OBJECTS, pFO->u32FenceHandle);
    210 
    211     /// @todo Pool of fence objects to avoid memory allocations.
    212     GaMemFree(pFO);
    213 }
    214 
    215 DECLINLINE(void) gaFenceRef(GAFENCEOBJECT *pFO)
    216 {
    217     ASMAtomicIncU32(&pFO->cRefs);
    218 }
    219 
    220 DECLINLINE(void) gaFenceUnref(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
    221 {
    222     uint32_t c = ASMAtomicDecU32(&pFO->cRefs);
    223     Assert(c < UINT32_MAX / 2);
    224     if (c == 0)
    225     {
    226         gaFenceDelete(pGaDevExt, pFO);
    227     }
    228 }
    229 
    230 DECLINLINE(void) gaFenceUnrefLocked(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)
    231 {
    232     uint32_t c = ASMAtomicDecU32(&pFO->cRefs);
    233     Assert(c < UINT32_MAX / 2);
    234     if (c == 0)
    235     {
    236         gaFenceDeleteLocked(pGaDevExt, pFO);
    237     }
    238 }
    239 
    240 static GAFENCEOBJECT *gaFenceLookup(VBOXWDDM_EXT_GA *pGaDevExt,
    241                                     uint32_t u32FenceHandle)
    242 {
    243     /* Must be called under the fence object lock. */
    244     GAFENCEOBJECT *pIter;
    245     RTListForEach(&pGaDevExt->fenceObjects.list, pIter, GAFENCEOBJECT, node)
    246     {
    247         if (pIter->u32FenceHandle == u32FenceHandle)
    248         {
    249             gaFenceRef(pIter);
    250             return pIter;
    251         }
    252     }
    253     return NULL;
    254 }
    255 
    256 
    25729void GaAdapterStop(PVBOXMP_DEVEXT pDevExt)
    25830{
     
    26335    {
    26436        /* Free fence objects. */
    265         gaFenceObjectsDestroy(pGaDevExt, NULL);
     37        GaFenceObjectsDestroy(pGaDevExt, NULL);
    26638
    26739        if (pGaDevExt->hw.pSvga)
     
    366138{
    367139    /* Free fence objects and GMRs. This is useful when the application has crashed.. */
    368     gaFenceObjectsDestroy(pGaDevExt, pDevice);
     140    GaFenceObjectsDestroy(pGaDevExt, pDevice);
    369141    SvgaRegionsDestroy(pGaDevExt->hw.pSvga, pDevice);
    370142}
     
    501273    if (pNode)
    502274        GaMemFree(pNode);
    503     return STATUS_SUCCESS;
    504 }
    505 
    506 
    507 /*
    508  * Fence objects.
    509  */
    510 
    511 NTSTATUS GaFenceCreate(PVBOXWDDM_EXT_GA pGaDevExt,
    512                        PVBOXWDDM_DEVICE pDevice,
    513                        uint32_t *pu32FenceHandle)
    514 {
    515     GAFENCEOBJECT *pFO = (GAFENCEOBJECT *)GaMemAllocZero(sizeof(GAFENCEOBJECT));
    516     if (!pFO)
    517         return STATUS_INSUFFICIENT_RESOURCES;
    518 
    519     /* pFO->cRefs             = 0; */
    520     pFO->u32FenceState      = GAFENCE_STATE_IDLE;
    521     /* pFO->fu32FenceFlags    = 0; */
    522     /* pFO->u32SubmissionFenceId    = 0; */
    523     pFO->u32SeqNo           = ASMAtomicIncU32(&pGaDevExt->fenceObjects.u32SeqNoSource);
    524     pFO->pDevice            = pDevice;
    525     /* RT_ZERO(pFO->event); */
    526 
    527     gaFenceObjectsLock(pGaDevExt);
    528 
    529     NTSTATUS Status = GaIdAlloc(pGaDevExt->fenceObjects.au32HandleBits, sizeof(pGaDevExt->fenceObjects.au32HandleBits),
    530                                 VBOXWDDM_GA_MAX_FENCE_OBJECTS, &pFO->u32FenceHandle);
    531     if (NT_SUCCESS(Status))
    532     {
    533         RTListAppend(&pGaDevExt->fenceObjects.list, &pFO->node);
    534         gaFenceRef(pFO);
    535 
    536         gaFenceObjectsUnlock(pGaDevExt);
    537 
    538         *pu32FenceHandle = pFO->u32FenceHandle;
    539 
    540         GALOG(("u32FenceHandle = %d\n", pFO->u32FenceHandle));
    541         return STATUS_SUCCESS;
    542     }
    543 
    544     /* Failure */
    545     gaFenceObjectsUnlock(pGaDevExt);
    546     GaMemFree(pFO);
    547     return Status;
    548 }
    549 
    550 NTSTATUS GaFenceQuery(PVBOXWDDM_EXT_GA pGaDevExt,
    551                       uint32_t u32FenceHandle,
    552                       uint32_t *pu32SubmittedSeqNo,
    553                       uint32_t *pu32ProcessedSeqNo,
    554                       uint32_t *pu32FenceStatus)
    555 {
    556     gaFenceObjectsLock(pGaDevExt);
    557 
    558     GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
    559 
    560     gaFenceObjectsUnlock(pGaDevExt);
    561 
    562     GALOG(("u32FenceHandle = %d, pFO %p\n", u32FenceHandle, pFO));
    563     if (pFO)
    564     {
    565         *pu32SubmittedSeqNo = pFO->u32SeqNo;
    566         switch (pFO->u32FenceState)
    567         {
    568             default:
    569                 AssertFailed();
    570                 RT_FALL_THRU();
    571             case GAFENCE_STATE_IDLE:      *pu32FenceStatus = GA_FENCE_STATUS_IDLE;      break;
    572             case GAFENCE_STATE_SUBMITTED: *pu32FenceStatus = GA_FENCE_STATUS_SUBMITTED; break;
    573             case GAFENCE_STATE_SIGNALED:  *pu32FenceStatus = GA_FENCE_STATUS_SIGNALED;  break;
    574         }
    575 
    576         gaFenceUnref(pGaDevExt, pFO);
    577     }
    578     else
    579     {
    580         *pu32SubmittedSeqNo = 0;
    581         *pu32FenceStatus = GA_FENCE_STATUS_NULL;
    582     }
    583     *pu32ProcessedSeqNo = ASMAtomicReadU32(&pGaDevExt->u32LastCompletedSeqNo);
    584 
    585     return STATUS_SUCCESS;
    586 }
    587 
    588 NTSTATUS GaFenceWait(PVBOXWDDM_EXT_GA pGaDevExt,
    589                      uint32_t u32FenceHandle,
    590                      uint32_t u32TimeoutUS)
    591 {
    592     gaFenceObjectsLock(pGaDevExt);
    593 
    594     GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
    595     AssertReturnStmt(pFO, gaFenceObjectsUnlock(pGaDevExt), STATUS_INVALID_PARAMETER);
    596 
    597     if (pFO->u32FenceState == GAFENCE_STATE_SIGNALED)
    598     {
    599         /* Already signaled. */
    600         gaFenceObjectsUnlock(pGaDevExt);
    601         gaFenceUnref(pGaDevExt, pFO);
    602         return STATUS_SUCCESS;
    603     }
    604 
    605     /* Wait */
    606     if (!RT_BOOL(pFO->fu32FenceFlags & GAFENCE_F_WAITED))
    607     {
    608         KeInitializeEvent(&pFO->event, NotificationEvent, FALSE);
    609         pFO->fu32FenceFlags |= GAFENCE_F_WAITED;
    610     }
    611 
    612     gaFenceObjectsUnlock(pGaDevExt);
    613 
    614     GALOG(("u32FenceHandle = %d, pFO %p\n", u32FenceHandle, pFO));
    615 
    616     LARGE_INTEGER Timeout;
    617     Timeout.QuadPart = u32TimeoutUS;
    618     Timeout.QuadPart *= -10LL; /* Microseconds to relative 100-nanoseconds units. */
    619     NTSTATUS Status = KeWaitForSingleObject(&pFO->event, UserRequest, KernelMode, TRUE, &Timeout);
    620 
    621     gaFenceUnref(pGaDevExt, pFO);
    622 
    623     return Status;
    624 }
    625 
    626 NTSTATUS GaFenceUnref(PVBOXWDDM_EXT_GA pGaDevExt,
    627                       uint32_t u32FenceHandle)
    628 {
    629     gaFenceObjectsLock(pGaDevExt);
    630 
    631     GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
    632     AssertReturnStmt(pFO, gaFenceObjectsUnlock(pGaDevExt), STATUS_INVALID_PARAMETER);
    633 
    634     if (RT_BOOL(pFO->fu32FenceFlags & GAFENCE_F_WAITED))
    635     {
    636         KeSetEvent(&pFO->event, 0, FALSE);
    637         pFO->fu32FenceFlags &= ~GAFENCE_F_WAITED;
    638     }
    639 
    640     gaFenceObjectsUnlock(pGaDevExt);
    641 
    642     GALOG(("u32FenceHandle = %d, pFO %p\n", u32FenceHandle, pFO));
    643 
    644     /* Undo gaFenceLookup ref. */
    645     gaFenceUnref(pGaDevExt, pFO);
    646 
    647     /* Undo the GaFenceCreate ref. */
    648     gaFenceUnref(pGaDevExt, pFO);
    649 
    650275    return STATUS_SUCCESS;
    651276}
     
    1296921                    /* Verify that the buffer handle is valid. */
    1297922                    gaFenceObjectsLock(pGaDevExt);
    1298                     pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);
     923                    pFO = GaFenceLookup(pGaDevExt, u32FenceHandle);
    1299924                    gaFenceObjectsUnlock(pGaDevExt);
    1300925
     
    17721397                }
    17731398
    1774                 gaFenceUnrefLocked(pGaDevExt, pIter);
     1399                GaFenceUnrefLocked(pGaDevExt, pIter);
    17751400            }
    17761401        }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette