Changeset 76884 in vbox for trunk/src/VBox/Additions/WINNT/Graphics/Video/mp
- Timestamp:
- Jan 18, 2019 10:45:23 AM (6 years ago)
- 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 180 180 wddm/gallium/SvgaFifo.cpp \ 181 181 wddm/gallium/SvgaHw.cpp \ 182 wddm/gallium/VBoxMPGaFence.cpp \ 183 wddm/gallium/VBoxMPGaUtils.cpp \ 182 184 wddm/gallium/VBoxMPGaWddm.cpp 183 185 endif -
trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPGaFence.cpp
r76845 r76884 18 18 #include "VBoxMPGaWddm.h" 19 19 #include "../VBoxMPVidPn.h" 20 #include "VBoxMPGaExt.h" 20 21 21 22 #include "Svga.h" … … 26 27 #include <iprt/time.h> 27 28 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) 29 void GaFenceObjectsDestroy(VBOXWDDM_EXT_GA *pGaDevExt, 30 PVBOXWDDM_DEVICE pDevice) 156 31 { 157 32 RTLISTANCHOR list; … … 228 103 } 229 104 230 DECLINLINE(void) gaFenceUnrefLocked(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO)105 void GaFenceUnrefLocked(VBOXWDDM_EXT_GA *pGaDevExt, GAFENCEOBJECT *pFO) 231 106 { 232 107 uint32_t c = ASMAtomicDecU32(&pFO->cRefs); … … 238 113 } 239 114 240 static GAFENCEOBJECT *gaFenceLookup(VBOXWDDM_EXT_GA *pGaDevExt,241 115 GAFENCEOBJECT *GaFenceLookup(VBOXWDDM_EXT_GA *pGaDevExt, 116 uint32_t u32FenceHandle) 242 117 { 243 118 /* Must be called under the fence object lock. */ … … 253 128 return NULL; 254 129 } 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 else307 {308 Status = STATUS_INSUFFICIENT_RESOURCES;309 }310 }311 else312 {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 else349 {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 else395 {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 else443 {444 SvgaSurfaceIdFree(pSvga, u32Sid);445 }446 }447 else448 {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 130 507 131 /* … … 556 180 gaFenceObjectsLock(pGaDevExt); 557 181 558 GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);182 GAFENCEOBJECT *pFO = GaFenceLookup(pGaDevExt, u32FenceHandle); 559 183 560 184 gaFenceObjectsUnlock(pGaDevExt); … … 592 216 gaFenceObjectsLock(pGaDevExt); 593 217 594 GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);218 GAFENCEOBJECT *pFO = GaFenceLookup(pGaDevExt, u32FenceHandle); 595 219 AssertReturnStmt(pFO, gaFenceObjectsUnlock(pGaDevExt), STATUS_INVALID_PARAMETER); 596 220 … … 629 253 gaFenceObjectsLock(pGaDevExt); 630 254 631 GAFENCEOBJECT *pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);255 GAFENCEOBJECT *pFO = GaFenceLookup(pGaDevExt, u32FenceHandle); 632 256 AssertReturnStmt(pFO, gaFenceObjectsUnlock(pGaDevExt), STATUS_INVALID_PARAMETER); 633 257 … … 642 266 GALOG(("u32FenceHandle = %d, pFO %p\n", u32FenceHandle, pFO)); 643 267 644 /* Undo gaFenceLookup ref. */268 /* Undo GaFenceLookup ref. */ 645 269 gaFenceUnref(pGaDevExt, pFO); 646 270 … … 650 274 return STATUS_SUCCESS; 651 275 } 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 < u32FenceB665 || 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(¬ify, 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, ¬ify);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 else753 {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 GARENDERDATA775 {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 1783 #define GARENDERDATA_TYPE_PRESENT 2784 #define GARENDERDATA_TYPE_PAGING 3785 #define GARENDERDATA_TYPE_FENCE 4786 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 4789 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->pDmaBuffer813 + 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_SHADOWSURFACE868 || 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_SHADOWSURFACE876 || 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_SHADOWSURFACE898 || 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 else934 {935 AssertFailed();936 }937 }938 else if ( pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE939 || 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->pDmaBuffer988 + 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 else998 {999 AssertFailed();1000 }1001 }1002 else1003 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 else1073 {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 11131 /* 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 #else1164 /* 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 #endif1175 }1176 else1177 {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 else1190 {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 else1220 {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->PatchLocationListOutSize1254 ));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 __try1262 {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 else1285 {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 else1320 {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, because1370 * 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 else1434 {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 else1462 {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 else1471 {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 else1514 {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 else1527 {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_RENDER1629 || 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 else1664 {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 GAPREEMPTCOMMANDCBCTX1783 {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 else1830 {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 else1952 {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 function1966 * 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 data1990 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 else2019 {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 pointer2164 pSource->AllocData.SurfDesc.bpp / 8, // dst bytes per pixel2165 pSource->AllocData.SurfDesc.pitch, // dst pitch2166 pPresentDisplayOnly->pSource, // src pointer2167 pPresentDisplayOnly->BytesPerPixel, // src bytes per pixel2168 pPresentDisplayOnly->Pitch, // src pitch2169 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 pointer2181 pSource->AllocData.SurfDesc.bpp / 8, // dst bytes per pixel2182 pSource->AllocData.SurfDesc.pitch, // dst pitch2183 pPresentDisplayOnly->pSource, // src pointer2184 pPresentDisplayOnly->BytesPerPixel, // src bytes per pixel2185 pPresentDisplayOnly->Pitch, // src pitch2186 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 16 16 */ 17 17 18 #include "VBoxMPGaWddm.h" 19 #include "../VBoxMPVidPn.h" 18 #include "VBoxMPGaUtils.h" 20 19 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> 27 22 28 23 volatile uint32_t g_fu32GaLogControl = … … 33 28 #endif 34 29 ; 35 36 37 #define VBOXWDDM_GA_MAX_FENCE_OBJECTS 409638 39 /* Gallium related device extension. */40 typedef struct VBOXWDDM_EXT_GA41 {42 union43 {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 struct55 {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 GAFENCEOBJECT70 {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 084 #define GAFENCE_STATE_SUBMITTED 185 #define GAFENCE_STATE_SIGNALED 286 87 #define GAFENCE_F_WAITED 0x1 /* KEVENT is initialized and there is(are) waiter(s). */88 89 30 90 31 /* … … 140 81 return STATUS_SUCCESS; 141 82 } 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 == NULL166 || 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 else307 {308 Status = STATUS_INSUFFICIENT_RESOURCES;309 }310 }311 else312 {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 else349 {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 else395 {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 else443 {444 SvgaSurfaceIdFree(pSvga, u32Sid);445 }446 }447 else448 {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 else579 {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 < u32FenceB665 || 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(¬ify, 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, ¬ify);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 else753 {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 GARENDERDATA775 {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 1783 #define GARENDERDATA_TYPE_PRESENT 2784 #define GARENDERDATA_TYPE_PAGING 3785 #define GARENDERDATA_TYPE_FENCE 4786 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 4789 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->pDmaBuffer813 + 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_SHADOWSURFACE868 || 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_SHADOWSURFACE876 || 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_SHADOWSURFACE898 || 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 else934 {935 AssertFailed();936 }937 }938 else if ( pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE939 || 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->pDmaBuffer988 + 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 else998 {999 AssertFailed();1000 }1001 }1002 else1003 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 else1073 {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 11131 /* 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 #else1164 /* 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 #endif1175 }1176 else1177 {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 else1190 {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 else1220 {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->PatchLocationListOutSize1254 ));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 __try1262 {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 else1285 {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 else1320 {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, because1370 * 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 else1434 {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 else1462 {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 else1471 {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 else1514 {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 else1527 {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_RENDER1629 || 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 else1664 {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 GAPREEMPTCOMMANDCBCTX1783 {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 else1830 {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 else1952 {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 function1966 * 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 data1990 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 else2019 {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 pointer2164 pSource->AllocData.SurfDesc.bpp / 8, // dst bytes per pixel2165 pSource->AllocData.SurfDesc.pitch, // dst pitch2166 pPresentDisplayOnly->pSource, // src pointer2167 pPresentDisplayOnly->BytesPerPixel, // src bytes per pixel2168 pPresentDisplayOnly->Pitch, // src pitch2169 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 pointer2181 pSource->AllocData.SurfDesc.bpp / 8, // dst bytes per pixel2182 pSource->AllocData.SurfDesc.pitch, // dst pitch2183 pPresentDisplayOnly->pSource, // src pointer2184 pPresentDisplayOnly->BytesPerPixel, // src bytes per pixel2185 pPresentDisplayOnly->Pitch, // src pitch2186 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 18 18 #include "VBoxMPGaWddm.h" 19 19 #include "../VBoxMPVidPn.h" 20 #include "VBoxMPGaExt.h" 20 21 21 22 #include "Svga.h" … … 26 27 #include <iprt/time.h> 27 28 28 volatile uint32_t g_fu32GaLogControl =29 #ifdef DEBUG30 1 /* Enable LogRels */31 #else32 0 /* Disable LogRels, but they can be enabled if necessary. */33 #endif34 ;35 36 37 #define VBOXWDDM_GA_MAX_FENCE_OBJECTS 409638 39 /* Gallium related device extension. */40 typedef struct VBOXWDDM_EXT_GA41 {42 union43 {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 struct55 {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 GAFENCEOBJECT70 {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 084 #define GAFENCE_STATE_SUBMITTED 185 #define GAFENCE_STATE_SIGNALED 286 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 == NULL166 || 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 29 void GaAdapterStop(PVBOXMP_DEVEXT pDevExt) 258 30 { … … 263 35 { 264 36 /* Free fence objects. */ 265 gaFenceObjectsDestroy(pGaDevExt, NULL);37 GaFenceObjectsDestroy(pGaDevExt, NULL); 266 38 267 39 if (pGaDevExt->hw.pSvga) … … 366 138 { 367 139 /* Free fence objects and GMRs. This is useful when the application has crashed.. */ 368 gaFenceObjectsDestroy(pGaDevExt, pDevice);140 GaFenceObjectsDestroy(pGaDevExt, pDevice); 369 141 SvgaRegionsDestroy(pGaDevExt->hw.pSvga, pDevice); 370 142 } … … 501 273 if (pNode) 502 274 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 else579 {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 275 return STATUS_SUCCESS; 651 276 } … … 1296 921 /* Verify that the buffer handle is valid. */ 1297 922 gaFenceObjectsLock(pGaDevExt); 1298 pFO = gaFenceLookup(pGaDevExt, u32FenceHandle);923 pFO = GaFenceLookup(pGaDevExt, u32FenceHandle); 1299 924 gaFenceObjectsUnlock(pGaDevExt); 1300 925 … … 1772 1397 } 1773 1398 1774 gaFenceUnrefLocked(pGaDevExt, pIter);1399 GaFenceUnrefLocked(pGaDevExt, pIter); 1775 1400 } 1776 1401 }
Note:
See TracChangeset
for help on using the changeset viewer.