VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPLegacy.cpp@ 89361

Last change on this file since 89361 was 86027, checked in by vboxsync, 4 years ago

WDDM: fix for VBoxVGA adapter

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.9 KB
Line 
1/* $Id: VBoxMPLegacy.cpp 86027 2020-09-03 17:45:50Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver. The legacy VBoxVGA adapter support with 2D software unaccelerated
4 * framebuffer operations.
5 */
6
7/*
8 * Copyright (C) 2011-2020 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "VBoxMPWddm.h"
20#include "common/VBoxMPCommon.h"
21#include "common/VBoxMPHGSMI.h"
22#ifdef VBOX_WITH_VIDEOHWACCEL
23# include "VBoxMPVhwa.h"
24#endif
25#include "VBoxMPVidPn.h"
26#include "VBoxMPLegacy.h"
27
28#include <iprt/alloc.h>
29#include <iprt/asm.h>
30#include <iprt/param.h>
31#include <iprt/initterm.h>
32
33#include <VBox/VBoxGuestLib.h>
34#include <VBox/VMMDev.h> /* for VMMDevVideoSetVisibleRegion */
35#include <VBoxVideo.h>
36#include <wingdi.h> /* needed for RGNDATA definition */
37#include <VBoxDisplay.h> /* this is from Additions/WINNT/include/ to include escape codes */
38#include <VBoxVideoVBE.h>
39#include <VBox/Version.h>
40
41
42/* ddi dma command queue handling */
43typedef enum
44{
45 VBOXVDMADDI_STATE_UNCKNOWN = 0,
46 VBOXVDMADDI_STATE_NOT_DX_CMD,
47 VBOXVDMADDI_STATE_NOT_QUEUED,
48 VBOXVDMADDI_STATE_PENDING,
49 VBOXVDMADDI_STATE_SUBMITTED,
50 VBOXVDMADDI_STATE_COMPLETED
51} VBOXVDMADDI_STATE;
52
53typedef struct VBOXVDMADDI_CMD *PVBOXVDMADDI_CMD;
54typedef DECLCALLBACKTYPE(VOID, FNVBOXVDMADDICMDCOMPLETE_DPC,(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext));
55typedef FNVBOXVDMADDICMDCOMPLETE_DPC *PFNVBOXVDMADDICMDCOMPLETE_DPC;
56
57typedef struct VBOXVDMADDI_CMD
58{
59 LIST_ENTRY QueueEntry;
60 VBOXVDMADDI_STATE enmState;
61 uint32_t u32NodeOrdinal;
62 uint32_t u32FenceId;
63 DXGK_INTERRUPT_TYPE enmComplType;
64 PFNVBOXVDMADDICMDCOMPLETE_DPC pfnComplete;
65 PVOID pvComplete;
66} VBOXVDMADDI_CMD, *PVBOXVDMADDI_CMD;
67
68#define VBOXVDMADDI_CMD_FROM_ENTRY(_pEntry) ((PVBOXVDMADDI_CMD)(((uint8_t*)(_pEntry)) - RT_OFFSETOF(VBOXVDMADDI_CMD, QueueEntry)))
69
70typedef struct VBOXWDDM_DMA_ALLOCINFO
71{
72 PVBOXWDDM_ALLOCATION pAlloc;
73 VBOXVIDEOOFFSET offAlloc;
74 UINT segmentIdAlloc : 31;
75 UINT fWriteOp : 1;
76 D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId;
77} VBOXWDDM_DMA_ALLOCINFO, *PVBOXWDDM_DMA_ALLOCINFO;
78
79typedef struct VBOXVDMAPIPE_RECTS
80{
81 RECT ContextRect;
82 VBOXWDDM_RECTS_INFO UpdateRects;
83} VBOXVDMAPIPE_RECTS, *PVBOXVDMAPIPE_RECTS;
84
85typedef struct VBOXVDMA_CLRFILL
86{
87 VBOXWDDM_DMA_ALLOCINFO Alloc;
88 UINT Color;
89 VBOXWDDM_RECTS_INFO Rects;
90} VBOXVDMA_CLRFILL, *PVBOXVDMA_CLRFILL;
91
92typedef struct VBOXVDMA_BLT
93{
94 VBOXWDDM_DMA_ALLOCINFO SrcAlloc;
95 VBOXWDDM_DMA_ALLOCINFO DstAlloc;
96 RECT SrcRect;
97 VBOXVDMAPIPE_RECTS DstRects;
98} VBOXVDMA_BLT, *PVBOXVDMA_BLT;
99
100typedef struct VBOXVDMA_FLIP
101{
102 VBOXWDDM_DMA_ALLOCINFO Alloc;
103} VBOXVDMA_FLIP, *PVBOXVDMA_FLIP;
104
105typedef struct VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR
106{
107 VBOXWDDM_DMA_PRIVATEDATA_BASEHDR BaseHdr;
108}VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR, *PVBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR;
109
110typedef struct VBOXWDDM_DMA_PRIVATEDATA_BLT
111{
112 VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR Hdr;
113 VBOXVDMA_BLT Blt;
114} VBOXWDDM_DMA_PRIVATEDATA_BLT, *PVBOXWDDM_DMA_PRIVATEDATA_BLT;
115
116typedef struct VBOXWDDM_DMA_PRIVATEDATA_FLIP
117{
118 VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR Hdr;
119 VBOXVDMA_FLIP Flip;
120} VBOXWDDM_DMA_PRIVATEDATA_FLIP, *PVBOXWDDM_DMA_PRIVATEDATA_FLIP;
121
122typedef struct VBOXWDDM_DMA_PRIVATEDATA_CLRFILL
123{
124 VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR Hdr;
125 VBOXVDMA_CLRFILL ClrFill;
126} VBOXWDDM_DMA_PRIVATEDATA_CLRFILL, *PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL;
127
128typedef enum
129{
130 VBOXWDDM_HGSMICMD_TYPE_UNDEFINED = 0,
131 VBOXWDDM_HGSMICMD_TYPE_CTL = 1,
132} VBOXWDDM_HGSMICMD_TYPE;
133
134VBOXWDDM_HGSMICMD_TYPE vboxWddmHgsmiGetCmdTypeFromOffset(PVBOXMP_DEVEXT pDevExt, HGSMIOFFSET offCmd)
135{
136 if (HGSMIAreaContainsOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx.Heap.area, offCmd))
137 return VBOXWDDM_HGSMICMD_TYPE_CTL;
138 return VBOXWDDM_HGSMICMD_TYPE_UNDEFINED;
139}
140
141VOID vboxVdmaDdiNodesInit(PVBOXMP_DEVEXT pDevExt)
142{
143 for (UINT i = 0; i < RT_ELEMENTS(pDevExt->aNodes); ++i)
144 {
145 pDevExt->aNodes[i].uLastCompletedFenceId = 0;
146 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[i].CmdQueue;
147 pQueue->cQueuedCmds = 0;
148 InitializeListHead(&pQueue->CmdQueue);
149 }
150 InitializeListHead(&pDevExt->DpcCmdQueue);
151}
152
153static VOID vboxVdmaDdiCmdNotifyCompletedIrq(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal, UINT u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
154{
155 PVBOXVDMADDI_NODE pNode = &pDevExt->aNodes[u32NodeOrdinal];
156 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
157 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
158 switch (enmComplType)
159 {
160 case DXGK_INTERRUPT_DMA_COMPLETED:
161 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
162 notify.DmaCompleted.SubmissionFenceId = u32FenceId;
163 notify.DmaCompleted.NodeOrdinal = u32NodeOrdinal;
164 pNode->uLastCompletedFenceId = u32FenceId;
165 break;
166
167 case DXGK_INTERRUPT_DMA_PREEMPTED:
168 Assert(0);
169 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
170 notify.DmaPreempted.PreemptionFenceId = u32FenceId;
171 notify.DmaPreempted.NodeOrdinal = u32NodeOrdinal;
172 notify.DmaPreempted.LastCompletedFenceId = pNode->uLastCompletedFenceId;
173 break;
174
175 case DXGK_INTERRUPT_DMA_FAULTED:
176 Assert(0);
177 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
178 notify.DmaFaulted.FaultedFenceId = u32FenceId;
179 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /** @todo better status ? */
180 notify.DmaFaulted.NodeOrdinal = u32NodeOrdinal;
181 break;
182
183 default:
184 Assert(0);
185 break;
186 }
187
188 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
189}
190
191static VOID vboxVdmaDdiCmdProcessCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
192{
193 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pCmd->u32NodeOrdinal, pCmd->u32FenceId, enmComplType);
194 switch (enmComplType)
195 {
196 case DXGK_INTERRUPT_DMA_COMPLETED:
197 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
198 break;
199 default:
200 AssertFailed();
201 break;
202 }
203}
204
205DECLINLINE(VOID) vboxVdmaDdiCmdDequeueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
206{
207 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
208 ASMAtomicDecU32(&pQueue->cQueuedCmds);
209 RemoveEntryList(&pCmd->QueueEntry);
210}
211
212DECLINLINE(VOID) vboxVdmaDdiCmdEnqueueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
213{
214 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
215 ASMAtomicIncU32(&pQueue->cQueuedCmds);
216 InsertTailList(&pQueue->CmdQueue, &pCmd->QueueEntry);
217}
218
219static BOOLEAN vboxVdmaDdiCmdCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
220{
221 if (VBOXVDMADDI_STATE_NOT_DX_CMD == pCmd->enmState)
222 {
223 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
224 return FALSE;
225 }
226
227 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
228 BOOLEAN bQueued = pCmd->enmState > VBOXVDMADDI_STATE_NOT_QUEUED;
229 BOOLEAN bComplete = FALSE;
230 Assert(!bQueued || pQueue->cQueuedCmds);
231 Assert(!bQueued || !IsListEmpty(&pQueue->CmdQueue));
232 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
233 if (bQueued)
234 {
235 if (pQueue->CmdQueue.Flink == &pCmd->QueueEntry)
236 {
237 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
238 bComplete = TRUE;
239 }
240 }
241 else if (IsListEmpty(&pQueue->CmdQueue))
242 {
243 bComplete = TRUE;
244 }
245 else
246 {
247 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
248 }
249
250 if (bComplete)
251 {
252 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, enmComplType);
253
254 while (!IsListEmpty(&pQueue->CmdQueue))
255 {
256 pCmd = VBOXVDMADDI_CMD_FROM_ENTRY(pQueue->CmdQueue.Flink);
257 if (pCmd->enmState == VBOXVDMADDI_STATE_COMPLETED)
258 {
259 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
260 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, pCmd->enmComplType);
261 }
262 else
263 break;
264 }
265 }
266 else
267 {
268 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
269 pCmd->enmComplType = enmComplType;
270 }
271
272 return bComplete;
273}
274
275typedef struct VBOXVDMADDI_CMD_COMPLETED_CB
276{
277 PVBOXMP_DEVEXT pDevExt;
278 PVBOXVDMADDI_CMD pCmd;
279 DXGK_INTERRUPT_TYPE enmComplType;
280} VBOXVDMADDI_CMD_COMPLETED_CB, *PVBOXVDMADDI_CMD_COMPLETED_CB;
281
282static BOOLEAN vboxVdmaDdiCmdCompletedCb(PVOID Context)
283{
284 PVBOXVDMADDI_CMD_COMPLETED_CB pdc = (PVBOXVDMADDI_CMD_COMPLETED_CB)Context;
285 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
286 BOOLEAN bNeedDpc = vboxVdmaDdiCmdCompletedIrq(pDevExt, pdc->pCmd, pdc->enmComplType);
287 pDevExt->bNotifyDxDpc |= bNeedDpc;
288
289 if (bNeedDpc)
290 {
291 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
292 }
293
294 return bNeedDpc;
295}
296
297static NTSTATUS vboxVdmaDdiCmdCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
298{
299 VBOXVDMADDI_CMD_COMPLETED_CB context;
300 context.pDevExt = pDevExt;
301 context.pCmd = pCmd;
302 context.enmComplType = enmComplType;
303 BOOLEAN bNeedDps;
304 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
305 pDevExt->u.primary.DxgkInterface.DeviceHandle,
306 vboxVdmaDdiCmdCompletedCb,
307 &context,
308 0, /* IN ULONG MessageNumber */
309 &bNeedDps);
310 AssertNtStatusSuccess(Status);
311 return Status;
312}
313
314DECLINLINE(VOID) vboxVdmaDdiCmdInit(PVBOXVDMADDI_CMD pCmd, uint32_t u32NodeOrdinal, uint32_t u32FenceId,
315 PFNVBOXVDMADDICMDCOMPLETE_DPC pfnComplete, PVOID pvComplete)
316{
317 pCmd->QueueEntry.Blink = NULL;
318 pCmd->QueueEntry.Flink = NULL;
319 pCmd->enmState = VBOXVDMADDI_STATE_NOT_QUEUED;
320 pCmd->u32NodeOrdinal = u32NodeOrdinal;
321 pCmd->u32FenceId = u32FenceId;
322 pCmd->pfnComplete = pfnComplete;
323 pCmd->pvComplete = pvComplete;
324}
325
326static DECLCALLBACK(VOID) vboxVdmaDdiCmdCompletionCbFree(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
327{
328 RT_NOREF(pDevExt, pvContext);
329 vboxWddmMemFree(pCmd);
330}
331
332DECLINLINE(BOOLEAN) vboxVdmaDdiCmdCanComplete(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal)
333{
334 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[u32NodeOrdinal].CmdQueue;
335 return ASMAtomicUoReadU32(&pQueue->cQueuedCmds) == 0;
336}
337
338typedef struct VBOXVDMADDI_CMD_COMPLETE_CB
339{
340 PVBOXMP_DEVEXT pDevExt;
341 UINT u32NodeOrdinal;
342 uint32_t u32FenceId;
343} VBOXVDMADDI_CMD_COMPLETE_CB, *PVBOXVDMADDI_CMD_COMPLETE_CB;
344
345static BOOLEAN vboxVdmaDdiCmdFenceCompleteCb(PVOID Context)
346{
347 PVBOXVDMADDI_CMD_COMPLETE_CB pdc = (PVBOXVDMADDI_CMD_COMPLETE_CB)Context;
348 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
349
350 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pdc->u32NodeOrdinal, pdc->u32FenceId, DXGK_INTERRUPT_DMA_COMPLETED);
351
352 pDevExt->bNotifyDxDpc = TRUE;
353 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
354
355 return TRUE;
356}
357
358static NTSTATUS vboxVdmaDdiCmdFenceNotifyComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId)
359{
360 VBOXVDMADDI_CMD_COMPLETE_CB context;
361 context.pDevExt = pDevExt;
362 context.u32NodeOrdinal = u32NodeOrdinal;
363 context.u32FenceId = u32FenceId;
364 BOOLEAN bRet;
365 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
366 pDevExt->u.primary.DxgkInterface.DeviceHandle,
367 vboxVdmaDdiCmdFenceCompleteCb,
368 &context,
369 0, /* IN ULONG MessageNumber */
370 &bRet);
371 AssertNtStatusSuccess(Status);
372 return Status;
373}
374
375static NTSTATUS vboxVdmaDdiCmdFenceComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
376{
377 if (vboxVdmaDdiCmdCanComplete(pDevExt, u32NodeOrdinal))
378 return vboxVdmaDdiCmdFenceNotifyComplete(pDevExt, u32NodeOrdinal, u32FenceId);
379
380 PVBOXVDMADDI_CMD pCmd = (PVBOXVDMADDI_CMD)vboxWddmMemAlloc(sizeof (VBOXVDMADDI_CMD));
381 Assert(pCmd);
382 if (pCmd)
383 {
384 vboxVdmaDdiCmdInit(pCmd, u32NodeOrdinal, u32FenceId, vboxVdmaDdiCmdCompletionCbFree, NULL);
385 NTSTATUS Status = vboxVdmaDdiCmdCompleted(pDevExt, pCmd, enmComplType);
386 AssertNtStatusSuccess(Status);
387 if (Status == STATUS_SUCCESS)
388 return STATUS_SUCCESS;
389 vboxWddmMemFree(pCmd);
390 return Status;
391 }
392 return STATUS_NO_MEMORY;
393}
394
395NTSTATUS vboxVdmaGgDmaBltPerform(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOC_DATA pSrcAlloc, RECT* pSrcRect,
396 PVBOXWDDM_ALLOC_DATA pDstAlloc, RECT* pDstRect)
397{
398 uint8_t* pvVramBase = pDevExt->pvVisibleVram;
399 /* we do not support stretching */
400 uint32_t srcWidth = pSrcRect->right - pSrcRect->left;
401 uint32_t srcHeight = pSrcRect->bottom - pSrcRect->top;
402 uint32_t dstWidth = pDstRect->right - pDstRect->left;
403 uint32_t dstHeight = pDstRect->bottom - pDstRect->top;
404 Assert(srcHeight == dstHeight);
405 Assert(dstWidth == srcWidth);
406 Assert(pDstAlloc->Addr.offVram != VBOXVIDEOOFFSET_VOID);
407 Assert(pSrcAlloc->Addr.offVram != VBOXVIDEOOFFSET_VOID);
408 D3DDDIFORMAT enmSrcFormat, enmDstFormat;
409
410 enmSrcFormat = pSrcAlloc->SurfDesc.format;
411 enmDstFormat = pDstAlloc->SurfDesc.format;
412
413 if (pDstAlloc->Addr.SegmentId && pDstAlloc->Addr.SegmentId != 1)
414 {
415 WARN(("request to collor blit invalid allocation"));
416 return STATUS_INVALID_PARAMETER;
417 }
418
419 if (pSrcAlloc->Addr.SegmentId && pSrcAlloc->Addr.SegmentId != 1)
420 {
421 WARN(("request to collor blit invalid allocation"));
422 return STATUS_INVALID_PARAMETER;
423 }
424
425 if (enmSrcFormat != enmDstFormat)
426 {
427 /* just ignore the alpha component
428 * this is ok since our software-based stuff can not handle alpha channel in any way */
429 enmSrcFormat = vboxWddmFmtNoAlphaFormat(enmSrcFormat);
430 enmDstFormat = vboxWddmFmtNoAlphaFormat(enmDstFormat);
431 if (enmSrcFormat != enmDstFormat)
432 {
433 WARN(("color conversion src(%d), dst(%d) not supported!", pSrcAlloc->SurfDesc.format, pDstAlloc->SurfDesc.format));
434 return STATUS_INVALID_PARAMETER;
435 }
436 }
437 if (srcHeight != dstHeight)
438 return STATUS_INVALID_PARAMETER;
439 if (srcWidth != dstWidth)
440 return STATUS_INVALID_PARAMETER;
441 if (pDstAlloc->Addr.offVram == VBOXVIDEOOFFSET_VOID)
442 return STATUS_INVALID_PARAMETER;
443 if (pSrcAlloc->Addr.offVram == VBOXVIDEOOFFSET_VOID)
444 return STATUS_INVALID_PARAMETER;
445
446 uint8_t *pvDstSurf = pDstAlloc->Addr.SegmentId ? pvVramBase + pDstAlloc->Addr.offVram : (uint8_t*)pDstAlloc->Addr.pvMem;
447 uint8_t *pvSrcSurf = pSrcAlloc->Addr.SegmentId ? pvVramBase + pSrcAlloc->Addr.offVram : (uint8_t*)pSrcAlloc->Addr.pvMem;
448
449 if (pDstAlloc->SurfDesc.width == dstWidth
450 && pSrcAlloc->SurfDesc.width == srcWidth
451 && pSrcAlloc->SurfDesc.width == pDstAlloc->SurfDesc.width)
452 {
453 Assert(!pDstRect->left);
454 Assert(!pSrcRect->left);
455 uint32_t cbDstOff = vboxWddmCalcOffXYrd(0 /* x */, pDstRect->top, pDstAlloc->SurfDesc.pitch, pDstAlloc->SurfDesc.format);
456 uint32_t cbSrcOff = vboxWddmCalcOffXYrd(0 /* x */, pSrcRect->top, pSrcAlloc->SurfDesc.pitch, pSrcAlloc->SurfDesc.format);
457 uint32_t cbSize = vboxWddmCalcSize(pDstAlloc->SurfDesc.pitch, dstHeight, pDstAlloc->SurfDesc.format);
458 memcpy(pvDstSurf + cbDstOff, pvSrcSurf + cbSrcOff, cbSize);
459 }
460 else
461 {
462 uint32_t cbDstLine = vboxWddmCalcRowSize(pDstRect->left, pDstRect->right, pDstAlloc->SurfDesc.format);
463 uint32_t offDstStart = vboxWddmCalcOffXYrd(pDstRect->left, pDstRect->top, pDstAlloc->SurfDesc.pitch, pDstAlloc->SurfDesc.format);
464 Assert(cbDstLine <= pDstAlloc->SurfDesc.pitch);
465 uint32_t cbDstSkip = pDstAlloc->SurfDesc.pitch;
466 uint8_t * pvDstStart = pvDstSurf + offDstStart;
467
468 uint32_t cbSrcLine = vboxWddmCalcRowSize(pSrcRect->left, pSrcRect->right, pSrcAlloc->SurfDesc.format);
469 uint32_t offSrcStart = vboxWddmCalcOffXYrd(pSrcRect->left, pSrcRect->top, pSrcAlloc->SurfDesc.pitch, pSrcAlloc->SurfDesc.format);
470 Assert(cbSrcLine <= pSrcAlloc->SurfDesc.pitch); NOREF(cbSrcLine);
471 uint32_t cbSrcSkip = pSrcAlloc->SurfDesc.pitch;
472 const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
473
474 uint32_t cRows = vboxWddmCalcNumRows(pDstRect->top, pDstRect->bottom, pDstAlloc->SurfDesc.format);
475
476 Assert(cbDstLine == cbSrcLine);
477
478 for (uint32_t i = 0; i < cRows; ++i)
479 {
480 memcpy(pvDstStart, pvSrcStart, cbDstLine);
481 pvDstStart += cbDstSkip;
482 pvSrcStart += cbSrcSkip;
483 }
484 }
485 return STATUS_SUCCESS;
486}
487
488static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXMP_DEVEXT pDevExt, VBOXVDMA_CLRFILL *pCF)
489{
490 NTSTATUS Status = STATUS_UNSUCCESSFUL;
491 Assert (pDevExt->pvVisibleVram);
492 if (pDevExt->pvVisibleVram)
493 {
494 PVBOXWDDM_ALLOCATION pAlloc = pCF->Alloc.pAlloc;
495 if (pAlloc->AllocData.Addr.SegmentId && pAlloc->AllocData.Addr.SegmentId != 1)
496 {
497 WARN(("request to collor fill invalid allocation"));
498 return STATUS_INVALID_PARAMETER;
499 }
500
501 VBOXVIDEOOFFSET offVram = vboxWddmAddrFramOffset(&pAlloc->AllocData.Addr);
502 if (offVram != VBOXVIDEOOFFSET_VOID)
503 {
504 RECT UnionRect = {0};
505 uint8_t *pvMem = pDevExt->pvVisibleVram + offVram;
506 UINT bpp = pAlloc->AllocData.SurfDesc.bpp;
507 Assert(bpp);
508 Assert(((bpp * pAlloc->AllocData.SurfDesc.width) >> 3) == pAlloc->AllocData.SurfDesc.pitch);
509 switch (bpp)
510 {
511 case 32:
512 {
513 uint8_t bytestPP = bpp >> 3;
514 for (UINT i = 0; i < pCF->Rects.cRects; ++i)
515 {
516 RECT *pRect = &pCF->Rects.aRects[i];
517 for (LONG ir = pRect->top; ir < pRect->bottom; ++ir)
518 {
519 uint32_t * pvU32Mem = (uint32_t*)(pvMem + (ir * pAlloc->AllocData.SurfDesc.pitch) + (pRect->left * bytestPP));
520 uint32_t cRaw = pRect->right - pRect->left;
521 Assert(pRect->left >= 0);
522 Assert(pRect->right <= (LONG)pAlloc->AllocData.SurfDesc.width);
523 Assert(pRect->top >= 0);
524 Assert(pRect->bottom <= (LONG)pAlloc->AllocData.SurfDesc.height);
525 for (UINT j = 0; j < cRaw; ++j)
526 {
527 *pvU32Mem = pCF->Color;
528 ++pvU32Mem;
529 }
530 }
531 vboxWddmRectUnited(&UnionRect, &UnionRect, pRect);
532 }
533 Status = STATUS_SUCCESS;
534 break;
535 }
536 case 16:
537 case 8:
538 default:
539 AssertBreakpoint();
540 break;
541 }
542
543 if (Status == STATUS_SUCCESS)
544 {
545 if (pAlloc->AllocData.SurfDesc.VidPnSourceId != D3DDDI_ID_UNINITIALIZED
546 && VBOXWDDM_IS_FB_ALLOCATION(pDevExt, pAlloc)
547 && pAlloc->bVisible
548 )
549 {
550 if (!vboxWddmRectIsEmpty(&UnionRect))
551 {
552 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pCF->Alloc.pAlloc->AllocData.SurfDesc.VidPnSourceId];
553 uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled);
554 if (!cUnlockedVBVADisabled)
555 {
556 VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &UnionRect);
557 }
558 else
559 {
560 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UnionRect);
561 }
562 }
563 }
564 else
565 {
566 AssertBreakpoint();
567 }
568 }
569 }
570 else
571 WARN(("invalid offVram"));
572 }
573
574 return Status;
575}
576
577static void vboxVdmaBltDirtyRectsUpdate(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_SOURCE *pSource, uint32_t cRects, const RECT *paRects)
578{
579 if (!cRects)
580 {
581 WARN(("vboxVdmaBltDirtyRectsUpdate: no rects specified"));
582 return;
583 }
584
585 RECT rect;
586 rect = paRects[0];
587 for (UINT i = 1; i < cRects; ++i)
588 {
589 vboxWddmRectUnited(&rect, &rect, &paRects[i]);
590 }
591
592 uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled);
593 if (!cUnlockedVBVADisabled)
594 {
595 VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &rect);
596 }
597 else
598 {
599 VBOXVBVA_OP_WITHLOCK_ATDPC(ReportDirtyRect, pDevExt, pSource, &rect);
600 }
601}
602
603/*
604 * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
605 */
606static NTSTATUS vboxVdmaGgDmaBlt(PVBOXMP_DEVEXT pDevExt, PVBOXVDMA_BLT pBlt)
607{
608 /* we do not support stretching for now */
609 Assert(pBlt->SrcRect.right - pBlt->SrcRect.left == pBlt->DstRects.ContextRect.right - pBlt->DstRects.ContextRect.left);
610 Assert(pBlt->SrcRect.bottom - pBlt->SrcRect.top == pBlt->DstRects.ContextRect.bottom - pBlt->DstRects.ContextRect.top);
611 if (pBlt->SrcRect.right - pBlt->SrcRect.left != pBlt->DstRects.ContextRect.right - pBlt->DstRects.ContextRect.left)
612 return STATUS_INVALID_PARAMETER;
613 if (pBlt->SrcRect.bottom - pBlt->SrcRect.top != pBlt->DstRects.ContextRect.bottom - pBlt->DstRects.ContextRect.top)
614 return STATUS_INVALID_PARAMETER;
615 Assert(pBlt->DstRects.UpdateRects.cRects);
616
617 NTSTATUS Status = STATUS_SUCCESS;
618
619 if (pBlt->DstRects.UpdateRects.cRects)
620 {
621 for (uint32_t i = 0; i < pBlt->DstRects.UpdateRects.cRects; ++i)
622 {
623 RECT SrcRect;
624 vboxWddmRectTranslated(&SrcRect, &pBlt->DstRects.UpdateRects.aRects[i], -pBlt->DstRects.ContextRect.left, -pBlt->DstRects.ContextRect.top);
625
626 Status = vboxVdmaGgDmaBltPerform(pDevExt, &pBlt->SrcAlloc.pAlloc->AllocData, &SrcRect,
627 &pBlt->DstAlloc.pAlloc->AllocData, &pBlt->DstRects.UpdateRects.aRects[i]);
628 AssertNtStatusSuccess(Status);
629 if (Status != STATUS_SUCCESS)
630 return Status;
631 }
632 }
633 else
634 {
635 Status = vboxVdmaGgDmaBltPerform(pDevExt, &pBlt->SrcAlloc.pAlloc->AllocData, &pBlt->SrcRect,
636 &pBlt->DstAlloc.pAlloc->AllocData, &pBlt->DstRects.ContextRect);
637 AssertNtStatusSuccess(Status);
638 if (Status != STATUS_SUCCESS)
639 return Status;
640 }
641
642 return Status;
643}
644
645static NTSTATUS vboxVdmaProcessBltCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_BLT *pBlt)
646{
647 RT_NOREF(pContext);
648 NTSTATUS Status = STATUS_SUCCESS;
649 PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc;
650// PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc;
651 {
652 /* the allocations contain a real data in VRAM, do blitting */
653 vboxVdmaGgDmaBlt(pDevExt, &pBlt->Blt);
654
655 if (pDstAlloc->bAssigned && pDstAlloc->bVisible)
656 {
657 /* Only for visible framebuffer allocations. */
658 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId];
659 /* Assert but otherwise ignore wrong allocations. */
660 AssertReturn(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS, STATUS_SUCCESS);
661 AssertReturn(pSource->pPrimaryAllocation == pDstAlloc, STATUS_SUCCESS);
662 vboxVdmaBltDirtyRectsUpdate(pDevExt, pSource, pBlt->Blt.DstRects.UpdateRects.cRects, pBlt->Blt.DstRects.UpdateRects.aRects);
663 }
664 }
665 return Status;
666}
667
668static NTSTATUS vboxVdmaProcessFlipCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_FLIP *pFlip)
669{
670 RT_NOREF(pContext);
671 NTSTATUS Status = STATUS_SUCCESS;
672 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
673 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
674 vboxWddmAssignPrimary(pSource, pAlloc, pAlloc->AllocData.SurfDesc.VidPnSourceId);
675 {
676 WARN(("unexpected flip request"));
677 }
678
679 return Status;
680}
681
682static NTSTATUS vboxVdmaProcessClrFillCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_CLRFILL *pCF)
683{
684 RT_NOREF(pContext);
685 NTSTATUS Status = STATUS_SUCCESS;
686// PVBOXWDDM_ALLOCATION pAlloc = pCF->ClrFill.Alloc.pAlloc;
687 {
688 Status = vboxVdmaGgDmaColorFill(pDevExt, &pCF->ClrFill);
689 if (!NT_SUCCESS(Status))
690 WARN(("vboxVdmaGgDmaColorFill failed Status 0x%x", Status));
691 }
692
693 return Status;
694}
695
696static void vboxWddmPatchLocationInit(D3DDDI_PATCHLOCATIONLIST *pPatchLocationListOut, UINT idx, UINT offPatch)
697{
698 memset(pPatchLocationListOut, 0, sizeof (*pPatchLocationListOut));
699 pPatchLocationListOut->AllocationIndex = idx;
700 pPatchLocationListOut->PatchOffset = offPatch;
701}
702
703static void vboxWddmPopulateDmaAllocInfo(PVBOXWDDM_DMA_ALLOCINFO pInfo, PVBOXWDDM_ALLOCATION pAlloc, DXGK_ALLOCATIONLIST *pDmaAlloc)
704{
705 pInfo->pAlloc = pAlloc;
706 if (pDmaAlloc->SegmentId)
707 {
708 pInfo->offAlloc = (VBOXVIDEOOFFSET)pDmaAlloc->PhysicalAddress.QuadPart;
709 pInfo->segmentIdAlloc = pDmaAlloc->SegmentId;
710 }
711 else
712 pInfo->segmentIdAlloc = 0;
713 pInfo->srcId = pAlloc->AllocData.SurfDesc.VidPnSourceId;
714}
715
716/*
717 *
718 * DxgkDdi
719 *
720 */
721
722NTSTATUS
723APIENTRY
724DxgkDdiBuildPagingBufferLegacy(
725 CONST HANDLE hAdapter,
726 DXGKARG_BUILDPAGINGBUFFER* pBuildPagingBuffer)
727{
728 /* DxgkDdiBuildPagingBuffer should be made pageable. */
729 PAGED_CODE();
730
731 vboxVDbgBreakFv();
732
733 NTSTATUS Status = STATUS_SUCCESS;
734 RT_NOREF(hAdapter);
735// PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
736
737 LOGF(("ENTER, context(0x%x)", hAdapter));
738
739 uint32_t cbCmdDma = 0;
740
741 /** @todo */
742 switch (pBuildPagingBuffer->Operation)
743 {
744 case DXGK_OPERATION_TRANSFER:
745 {
746 cbCmdDma = VBOXWDDM_DUMMY_DMABUFFER_SIZE;
747#ifdef VBOX_WITH_VDMA
748 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pBuildPagingBuffer->Transfer.hAllocation;
749 Assert(pAlloc);
750 if (pAlloc
751 && !pAlloc->fRcFlags.Overlay /* overlay surfaces actually contain a valid data */
752 && pAlloc->enmType != VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE /* shadow primary - also */
753 && pAlloc->enmType != VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER /* hgsmi buffer - also */
754 )
755 {
756 /* we do not care about the others for now */
757 Status = STATUS_SUCCESS;
758 break;
759 }
760 UINT cbCmd = VBOXVDMACMD_SIZE(VBOXVDMACMD_DMA_BPB_TRANSFER);
761 VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_HOST *pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbCmd);
762 Assert(pDr);
763 if (pDr)
764 {
765 SIZE_T cbTransfered = 0;
766 SIZE_T cbTransferSize = pBuildPagingBuffer->Transfer.TransferSize;
767 VBOXVDMACMD RT_UNTRUSTED_VOLATILE_HOST *pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
768 do
769 {
770 // vboxVdmaCBufDrCreate zero initializes the pDr
771 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
772 pDr->cbBuf = cbCmd;
773 pDr->rc = VERR_NOT_IMPLEMENTED;
774
775 pHdr->enmType = VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER;
776 pHdr->u32CmdSpecific = 0;
777 VBOXVDMACMD_DMA_BPB_TRANSFER RT_UNTRUSTED_VOLATILE_HOST *pBody
778 = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_DMA_BPB_TRANSFER);
779// pBody->cbTransferSize = (uint32_t)pBuildPagingBuffer->Transfer.TransferSize;
780 pBody->fFlags = 0;
781 SIZE_T cSrcPages = (cbTransferSize + 0xfff ) >> 12;
782 SIZE_T cDstPages = cSrcPages;
783
784 if (pBuildPagingBuffer->Transfer.Source.SegmentId)
785 {
786 uint64_t off = pBuildPagingBuffer->Transfer.Source.SegmentAddress.QuadPart;
787 off += pBuildPagingBuffer->Transfer.TransferOffset + cbTransfered;
788 pBody->Src.offVramBuf = off;
789 pBody->fFlags |= VBOXVDMACMD_DMA_BPB_TRANSFER_F_SRC_VRAMOFFSET;
790 }
791 else
792 {
793 UINT index = pBuildPagingBuffer->Transfer.MdlOffset + (UINT)(cbTransfered>>12);
794 pBody->Src.phBuf = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Source.pMdl)[index] << PAGE_SHIFT;
795 PFN_NUMBER num = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Source.pMdl)[index];
796 cSrcPages = 1;
797 for (UINT i = 1; i < ((cbTransferSize - cbTransfered + 0xfff) >> 12); ++i)
798 {
799 PFN_NUMBER cur = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Source.pMdl)[index+i];
800 if(cur != ++num)
801 {
802 cSrcPages+= i-1;
803 break;
804 }
805 }
806 }
807
808 if (pBuildPagingBuffer->Transfer.Destination.SegmentId)
809 {
810 uint64_t off = pBuildPagingBuffer->Transfer.Destination.SegmentAddress.QuadPart;
811 off += pBuildPagingBuffer->Transfer.TransferOffset;
812 pBody->Dst.offVramBuf = off + cbTransfered;
813 pBody->fFlags |= VBOXVDMACMD_DMA_BPB_TRANSFER_F_DST_VRAMOFFSET;
814 }
815 else
816 {
817 UINT index = pBuildPagingBuffer->Transfer.MdlOffset + (UINT)(cbTransfered>>12);
818 pBody->Dst.phBuf = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Destination.pMdl)[index] << PAGE_SHIFT;
819 PFN_NUMBER num = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Destination.pMdl)[index];
820 cDstPages = 1;
821 for (UINT i = 1; i < ((cbTransferSize - cbTransfered + 0xfff) >> 12); ++i)
822 {
823 PFN_NUMBER cur = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Destination.pMdl)[index+i];
824 if(cur != ++num)
825 {
826 cDstPages+= i-1;
827 break;
828 }
829 }
830 }
831
832 SIZE_T cbCurTransfer;
833 cbCurTransfer = RT_MIN(cbTransferSize - cbTransfered, (SIZE_T)cSrcPages << PAGE_SHIFT);
834 cbCurTransfer = RT_MIN(cbCurTransfer, (SIZE_T)cDstPages << PAGE_SHIFT);
835
836 pBody->cbTransferSize = (UINT)cbCurTransfer;
837 Assert(!(cbCurTransfer & 0xfff));
838
839 int rc = vboxVdmaCBufDrSubmitSynch(pDevExt, &pDevExt->u.primary.Vdma, pDr);
840 AssertRC(rc);
841 if (RT_SUCCESS(rc))
842 {
843 Status = STATUS_SUCCESS;
844 cbTransfered += cbCurTransfer;
845 }
846 else
847 Status = STATUS_UNSUCCESSFUL;
848 } while (cbTransfered < cbTransferSize);
849 Assert(cbTransfered == cbTransferSize);
850 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
851 }
852 else
853 {
854 /** @todo try flushing.. */
855 LOGREL(("vboxVdmaCBufDrCreate returned NULL"));
856 Status = STATUS_INSUFFICIENT_RESOURCES;
857 }
858#endif /* #ifdef VBOX_WITH_VDMA */
859 break;
860 }
861 case DXGK_OPERATION_FILL:
862 {
863 cbCmdDma = VBOXWDDM_DUMMY_DMABUFFER_SIZE;
864 Assert(pBuildPagingBuffer->Fill.FillPattern == 0);
865 /*PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pBuildPagingBuffer->Fill.hAllocation; - unused. Incomplete code? */
866// pBuildPagingBuffer->pDmaBuffer = (uint8_t*)pBuildPagingBuffer->pDmaBuffer + VBOXVDMACMD_SIZE(VBOXVDMACMD_DMA_BPB_FILL);
867 break;
868 }
869 case DXGK_OPERATION_DISCARD_CONTENT:
870 {
871// AssertBreakpoint();
872 break;
873 }
874 default:
875 {
876 WARN(("unsupported op (%d)", pBuildPagingBuffer->Operation));
877 break;
878 }
879 }
880
881 if (cbCmdDma)
882 {
883 pBuildPagingBuffer->pDmaBuffer = ((uint8_t*)pBuildPagingBuffer->pDmaBuffer) + cbCmdDma;
884 }
885
886 LOGF(("LEAVE, context(0x%x)", hAdapter));
887
888 return Status;
889
890}
891
892/**
893 * DxgkDdiPresent
894 */
895NTSTATUS
896APIENTRY
897DxgkDdiPresentLegacy(
898 CONST HANDLE hContext,
899 DXGKARG_PRESENT *pPresent)
900{
901 RT_NOREF(hContext);
902 PAGED_CODE();
903
904// LOGF(("ENTER, hContext(0x%x)", hContext));
905
906 vboxVDbgBreakFv();
907
908 NTSTATUS Status = STATUS_SUCCESS;
909#ifdef VBOX_STRICT
910 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
911 PVBOXWDDM_DEVICE pDevice = pContext->pDevice;
912 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
913#endif
914
915 Assert(pPresent->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR));
916 if (pPresent->DmaBufferPrivateDataSize < sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR))
917 {
918 LOGREL(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR (%d)", pPresent->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)));
919 /** @todo can this actually happen? what status tu return? */
920 return STATUS_INVALID_PARAMETER;
921 }
922
923 PVBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR pPrivateData = (PVBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)pPresent->pDmaBufferPrivateData;
924 pPrivateData->BaseHdr.fFlags.Value = 0;
925 /*uint32_t cContexts2D = ASMAtomicReadU32(&pDevExt->cContexts2D); - unused */
926
927 if (pPresent->Flags.Blt)
928 {
929 Assert(pPresent->Flags.Value == 1); /* only Blt is set, we do not support anything else for now */
930 DXGK_ALLOCATIONLIST *pSrc = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX];
931 DXGK_ALLOCATIONLIST *pDst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX];
932 PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pSrc);
933 if (!pSrcAlloc)
934 {
935 /* this should not happen actually */
936 WARN(("failed to get Src Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation));
937 Status = STATUS_INVALID_HANDLE;
938 goto done;
939 }
940
941 PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDst);
942 if (!pDstAlloc)
943 {
944 /* this should not happen actually */
945 WARN(("failed to get Dst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation));
946 Status = STATUS_INVALID_HANDLE;
947 goto done;
948 }
949
950
951 UINT cbCmd = pPresent->DmaBufferPrivateDataSize;
952 pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_BLT;
953
954 PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt = (PVBOXWDDM_DMA_PRIVATEDATA_BLT)pPrivateData;
955
956 vboxWddmPopulateDmaAllocInfo(&pBlt->Blt.SrcAlloc, pSrcAlloc, pSrc);
957 vboxWddmPopulateDmaAllocInfo(&pBlt->Blt.DstAlloc, pDstAlloc, pDst);
958
959 ASSERT_WARN(!pSrcAlloc->fRcFlags.SharedResource, ("Shared Allocatoin used in Present!"));
960
961 pBlt->Blt.SrcRect = pPresent->SrcRect;
962 pBlt->Blt.DstRects.ContextRect = pPresent->DstRect;
963 pBlt->Blt.DstRects.UpdateRects.cRects = 0;
964 UINT cbHead = RT_UOFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_BLT, Blt.DstRects.UpdateRects.aRects[0]);
965 Assert(pPresent->SubRectCnt > pPresent->MultipassOffset);
966 UINT cbRects = (pPresent->SubRectCnt - pPresent->MultipassOffset) * sizeof (RECT);
967 pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE;
968 Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE);
969 cbCmd -= cbHead;
970 Assert(cbCmd < UINT32_MAX/2);
971 Assert(cbCmd > sizeof (RECT));
972 if (cbCmd >= cbRects)
973 {
974 cbCmd -= cbRects;
975 memcpy(&pBlt->Blt.DstRects.UpdateRects.aRects[0], &pPresent->pDstSubRects[pPresent->MultipassOffset], cbRects);
976 pBlt->Blt.DstRects.UpdateRects.cRects += cbRects/sizeof (RECT);
977
978 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbRects;
979 }
980 else
981 {
982 UINT cbFitingRects = (cbCmd/sizeof (RECT)) * sizeof (RECT);
983 Assert(cbFitingRects);
984 memcpy(&pBlt->Blt.DstRects.UpdateRects.aRects[0], &pPresent->pDstSubRects[pPresent->MultipassOffset], cbFitingRects);
985 cbCmd -= cbFitingRects;
986 pPresent->MultipassOffset += cbFitingRects/sizeof (RECT);
987 pBlt->Blt.DstRects.UpdateRects.cRects += cbFitingRects/sizeof (RECT);
988 Assert(pPresent->SubRectCnt > pPresent->MultipassOffset);
989
990 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbFitingRects;
991 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
992 }
993
994 memset(pPresent->pPatchLocationListOut, 0, 2*sizeof (D3DDDI_PATCHLOCATIONLIST));
995 pPresent->pPatchLocationListOut->PatchOffset = 0;
996 pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX;
997 ++pPresent->pPatchLocationListOut;
998 pPresent->pPatchLocationListOut->PatchOffset = 4;
999 pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX;
1000 ++pPresent->pPatchLocationListOut;
1001 }
1002 else if (pPresent->Flags.Flip)
1003 {
1004 Assert(pPresent->Flags.Value == 4); /* only Blt is set, we do not support anything else for now */
1005 //Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D);
1006 DXGK_ALLOCATIONLIST *pSrc = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX];
1007 PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pSrc);
1008
1009 if (!pSrcAlloc)
1010 {
1011 /* this should not happen actually */
1012 WARN(("failed to get pSrc Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation));
1013 Status = STATUS_INVALID_HANDLE;
1014 goto done;
1015 }
1016
1017 Assert(pDevExt->cContexts3D);
1018 pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP;
1019 PVBOXWDDM_DMA_PRIVATEDATA_FLIP pFlip = (PVBOXWDDM_DMA_PRIVATEDATA_FLIP)pPrivateData;
1020
1021 vboxWddmPopulateDmaAllocInfo(&pFlip->Flip.Alloc, pSrcAlloc, pSrc);
1022
1023 UINT cbCmd = sizeof (VBOXWDDM_DMA_PRIVATEDATA_FLIP);
1024 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbCmd;
1025 pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE;
1026 Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE);
1027
1028 memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST));
1029 pPresent->pPatchLocationListOut->PatchOffset = 0;
1030 pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX;
1031 ++pPresent->pPatchLocationListOut;
1032 }
1033 else if (pPresent->Flags.ColorFill)
1034 {
1035 //Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_2D);
1036 Assert(pPresent->Flags.Value == 2); /* only ColorFill is set, we do not support anything else for now */
1037 DXGK_ALLOCATIONLIST *pDst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX];
1038 PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDst);
1039 if (!pDstAlloc)
1040 {
1041
1042 /* this should not happen actually */
1043 WARN(("failed to get pDst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation));
1044 Status = STATUS_INVALID_HANDLE;
1045 goto done;
1046 }
1047
1048 UINT cbCmd = pPresent->DmaBufferPrivateDataSize;
1049 pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL;
1050 PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL pCF = (PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL)pPrivateData;
1051
1052 vboxWddmPopulateDmaAllocInfo(&pCF->ClrFill.Alloc, pDstAlloc, pDst);
1053
1054 pCF->ClrFill.Color = pPresent->Color;
1055 pCF->ClrFill.Rects.cRects = 0;
1056 UINT cbHead = RT_UOFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_CLRFILL, ClrFill.Rects.aRects[0]);
1057 Assert(pPresent->SubRectCnt > pPresent->MultipassOffset);
1058 UINT cbRects = (pPresent->SubRectCnt - pPresent->MultipassOffset) * sizeof (RECT);
1059 pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE;
1060 Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE);
1061 cbCmd -= cbHead;
1062 Assert(cbCmd < UINT32_MAX/2);
1063 Assert(cbCmd > sizeof (RECT));
1064 if (cbCmd >= cbRects)
1065 {
1066 cbCmd -= cbRects;
1067 memcpy(&pCF->ClrFill.Rects.aRects[pPresent->MultipassOffset], pPresent->pDstSubRects, cbRects);
1068 pCF->ClrFill.Rects.cRects += cbRects/sizeof (RECT);
1069
1070 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbRects;
1071 }
1072 else
1073 {
1074 UINT cbFitingRects = (cbCmd/sizeof (RECT)) * sizeof (RECT);
1075 Assert(cbFitingRects);
1076 memcpy(&pCF->ClrFill.Rects.aRects[0], pPresent->pDstSubRects, cbFitingRects);
1077 cbCmd -= cbFitingRects;
1078 pPresent->MultipassOffset += cbFitingRects/sizeof (RECT);
1079 pCF->ClrFill.Rects.cRects += cbFitingRects/sizeof (RECT);
1080 Assert(pPresent->SubRectCnt > pPresent->MultipassOffset);
1081
1082 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbFitingRects;
1083 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
1084 }
1085
1086 memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST));
1087 pPresent->pPatchLocationListOut->PatchOffset = 0;
1088 pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX;
1089 ++pPresent->pPatchLocationListOut;
1090 }
1091 else
1092 {
1093 WARN(("cmd NOT IMPLEMENTED!! Flags(0x%x)", pPresent->Flags.Value));
1094 Status = STATUS_NOT_SUPPORTED;
1095 }
1096
1097done:
1098// LOGF(("LEAVE, hContext(0x%x), Status(0x%x)", hContext, Status));
1099
1100 return Status;
1101}
1102
1103NTSTATUS
1104APIENTRY
1105DxgkDdiRenderLegacy(
1106 CONST HANDLE hContext,
1107 DXGKARG_RENDER *pRender)
1108{
1109 RT_NOREF(hContext);
1110// LOGF(("ENTER, hContext(0x%x)", hContext));
1111
1112 if (pRender->DmaBufferPrivateDataSize < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))
1113 {
1114 WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_BASEHDR (%d)",
1115 pRender->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)));
1116 return STATUS_INVALID_PARAMETER;
1117 }
1118 if (pRender->CommandLength < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))
1119 {
1120 WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_BASEHDR (%d)",
1121 pRender->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)));
1122 return STATUS_INVALID_PARAMETER;
1123 }
1124 if (pRender->DmaSize < pRender->CommandLength)
1125 {
1126 WARN(("pRender->DmaSize(%d) < pRender->CommandLength(%d)",
1127 pRender->DmaSize, pRender->CommandLength));
1128 return STATUS_INVALID_PARAMETER;
1129 }
1130 if (pRender->PatchLocationListOutSize < pRender->PatchLocationListInSize)
1131 {
1132 WARN(("pRender->PatchLocationListOutSize(%d) < pRender->PatchLocationListInSize(%d)",
1133 pRender->PatchLocationListOutSize, pRender->PatchLocationListInSize));
1134 return STATUS_INVALID_PARAMETER;
1135 }
1136 if (pRender->AllocationListSize != pRender->PatchLocationListInSize)
1137 {
1138 WARN(("pRender->AllocationListSize(%d) != pRender->PatchLocationListInSize(%d)",
1139 pRender->AllocationListSize, pRender->PatchLocationListInSize));
1140 return STATUS_INVALID_PARAMETER;
1141 }
1142
1143 NTSTATUS Status = STATUS_SUCCESS;
1144
1145 __try
1146 {
1147 PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pInputHdr = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender->pCommand;
1148 switch (pInputHdr->enmCmd)
1149 {
1150 case VBOXVDMACMD_TYPE_DMA_NOP:
1151 {
1152 PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pPrivateData = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender->pDmaBufferPrivateData;
1153 pPrivateData->enmCmd = VBOXVDMACMD_TYPE_DMA_NOP;
1154 pRender->pDmaBufferPrivateData = (uint8_t*)pRender->pDmaBufferPrivateData + sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR);
1155 pRender->pDmaBuffer = ((uint8_t*)pRender->pDmaBuffer) + pRender->CommandLength;
1156 for (UINT i = 0; i < pRender->PatchLocationListInSize; ++i)
1157 {
1158 UINT offPatch = i * 4;
1159 if (offPatch + 4 > pRender->CommandLength)
1160 {
1161 WARN(("wrong offPatch"));
1162 return STATUS_INVALID_PARAMETER;
1163 }
1164 if (offPatch != pRender->pPatchLocationListIn[i].PatchOffset)
1165 {
1166 WARN(("wrong PatchOffset"));
1167 return STATUS_INVALID_PARAMETER;
1168 }
1169 if (i != pRender->pPatchLocationListIn[i].AllocationIndex)
1170 {
1171 WARN(("wrong AllocationIndex"));
1172 return STATUS_INVALID_PARAMETER;
1173 }
1174 vboxWddmPatchLocationInit(&pRender->pPatchLocationListOut[i], i, offPatch);
1175 }
1176 break;
1177 }
1178 default:
1179 {
1180 WARN(("unsupported command %d", pInputHdr->enmCmd));
1181 return STATUS_INVALID_PARAMETER;
1182 }
1183 }
1184 }
1185 __except (EXCEPTION_EXECUTE_HANDLER)
1186 {
1187 Status = STATUS_INVALID_PARAMETER;
1188 WARN(("invalid parameter"));
1189 }
1190// LOGF(("LEAVE, hContext(0x%x)", hContext));
1191
1192 return Status;
1193}
1194
1195NTSTATUS
1196APIENTRY
1197DxgkDdiPatchLegacy(
1198 CONST HANDLE hAdapter,
1199 CONST DXGKARG_PATCH* pPatch)
1200{
1201 RT_NOREF(hAdapter);
1202 /* DxgkDdiPatch should be made pageable. */
1203 PAGED_CODE();
1204
1205 NTSTATUS Status = STATUS_SUCCESS;
1206
1207 LOGF(("ENTER, context(0x%x)", hAdapter));
1208
1209 vboxVDbgBreakFv();
1210
1211 /* Value == 2 is Present
1212 * Value == 4 is RedirectedPresent
1213 * we do not expect any other flags to be set here */
1214// Assert(pPatch->Flags.Value == 2 || pPatch->Flags.Value == 4);
1215 if (pPatch->DmaBufferPrivateDataSubmissionEndOffset - pPatch->DmaBufferPrivateDataSubmissionStartOffset >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))
1216 {
1217 Assert(pPatch->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR));
1218 VBOXWDDM_DMA_PRIVATEDATA_BASEHDR *pPrivateDataBase = (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR*)((uint8_t*)pPatch->pDmaBufferPrivateData + pPatch->DmaBufferPrivateDataSubmissionStartOffset);
1219 switch (pPrivateDataBase->enmCmd)
1220 {
1221 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
1222 {
1223 PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt = (PVBOXWDDM_DMA_PRIVATEDATA_BLT)pPrivateDataBase;
1224 Assert(pPatch->PatchLocationListSubmissionLength == 2);
1225 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[pPatch->PatchLocationListSubmissionStart];
1226 Assert(pPatchList->AllocationIndex == DXGK_PRESENT_SOURCE_INDEX);
1227 Assert(pPatchList->PatchOffset == 0);
1228 const DXGK_ALLOCATIONLIST *pSrcAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1229 Assert(pSrcAllocationList->SegmentId);
1230 pBlt->Blt.SrcAlloc.segmentIdAlloc = pSrcAllocationList->SegmentId;
1231 pBlt->Blt.SrcAlloc.offAlloc = (VBOXVIDEOOFFSET)pSrcAllocationList->PhysicalAddress.QuadPart;
1232
1233 pPatchList = &pPatch->pPatchLocationList[pPatch->PatchLocationListSubmissionStart + 1];
1234 Assert(pPatchList->AllocationIndex == DXGK_PRESENT_DESTINATION_INDEX);
1235 Assert(pPatchList->PatchOffset == 4);
1236 const DXGK_ALLOCATIONLIST *pDstAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1237 Assert(pDstAllocationList->SegmentId);
1238 pBlt->Blt.DstAlloc.segmentIdAlloc = pDstAllocationList->SegmentId;
1239 pBlt->Blt.DstAlloc.offAlloc = (VBOXVIDEOOFFSET)pDstAllocationList->PhysicalAddress.QuadPart;
1240 break;
1241 }
1242 case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP:
1243 {
1244 PVBOXWDDM_DMA_PRIVATEDATA_FLIP pFlip = (PVBOXWDDM_DMA_PRIVATEDATA_FLIP)pPrivateDataBase;
1245 Assert(pPatch->PatchLocationListSubmissionLength == 1);
1246 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[pPatch->PatchLocationListSubmissionStart];
1247 Assert(pPatchList->AllocationIndex == DXGK_PRESENT_SOURCE_INDEX);
1248 Assert(pPatchList->PatchOffset == 0);
1249 const DXGK_ALLOCATIONLIST *pSrcAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1250 Assert(pSrcAllocationList->SegmentId);
1251 pFlip->Flip.Alloc.segmentIdAlloc = pSrcAllocationList->SegmentId;
1252 pFlip->Flip.Alloc.offAlloc = (VBOXVIDEOOFFSET)pSrcAllocationList->PhysicalAddress.QuadPart;
1253 break;
1254 }
1255 case VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL:
1256 {
1257 PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL pCF = (PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL)pPrivateDataBase;
1258 Assert(pPatch->PatchLocationListSubmissionLength == 1);
1259 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[pPatch->PatchLocationListSubmissionStart];
1260 Assert(pPatchList->AllocationIndex == DXGK_PRESENT_DESTINATION_INDEX);
1261 Assert(pPatchList->PatchOffset == 0);
1262 const DXGK_ALLOCATIONLIST *pDstAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1263 Assert(pDstAllocationList->SegmentId);
1264 pCF->ClrFill.Alloc.segmentIdAlloc = pDstAllocationList->SegmentId;
1265 pCF->ClrFill.Alloc.offAlloc = (VBOXVIDEOOFFSET)pDstAllocationList->PhysicalAddress.QuadPart;
1266 break;
1267 }
1268 case VBOXVDMACMD_TYPE_DMA_NOP:
1269 break;
1270 case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
1271 {
1272 uint8_t * pPrivateBuf = (uint8_t*)pPrivateDataBase;
1273 for (UINT i = pPatch->PatchLocationListSubmissionStart; i < pPatch->PatchLocationListSubmissionLength; ++i)
1274 {
1275 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[i];
1276 Assert(pPatchList->AllocationIndex < pPatch->AllocationListSize);
1277 const DXGK_ALLOCATIONLIST *pAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1278 Assert(pAllocationList->SegmentId);
1279 if (pAllocationList->SegmentId)
1280 {
1281 DXGK_ALLOCATIONLIST *pAllocation2Patch = (DXGK_ALLOCATIONLIST*)(pPrivateBuf + pPatchList->PatchOffset);
1282 pAllocation2Patch->SegmentId = pAllocationList->SegmentId;
1283 pAllocation2Patch->PhysicalAddress.QuadPart = pAllocationList->PhysicalAddress.QuadPart + pPatchList->AllocationOffset;
1284 Assert(!(pAllocationList->PhysicalAddress.QuadPart & 0xfffUL)); /* <- just a check to ensure allocation offset does not go here */
1285 }
1286 }
1287 break;
1288 }
1289 default:
1290 {
1291 AssertBreakpoint();
1292 uint8_t *pBuf = ((uint8_t *)pPatch->pDmaBuffer) + pPatch->DmaBufferSubmissionStartOffset;
1293 for (UINT i = pPatch->PatchLocationListSubmissionStart; i < pPatch->PatchLocationListSubmissionLength; ++i)
1294 {
1295 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[i];
1296 Assert(pPatchList->AllocationIndex < pPatch->AllocationListSize);
1297 const DXGK_ALLOCATIONLIST *pAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1298 if (pAllocationList->SegmentId)
1299 {
1300 Assert(pPatchList->PatchOffset < (pPatch->DmaBufferSubmissionEndOffset - pPatch->DmaBufferSubmissionStartOffset));
1301 *((VBOXVIDEOOFFSET*)(pBuf+pPatchList->PatchOffset)) = (VBOXVIDEOOFFSET)pAllocationList->PhysicalAddress.QuadPart;
1302 }
1303 else
1304 {
1305 /* sanity */
1306 if (pPatch->Flags.Value == 2 || pPatch->Flags.Value == 4)
1307 Assert(i == 0);
1308 }
1309 }
1310 break;
1311 }
1312 }
1313 }
1314 else if (pPatch->DmaBufferPrivateDataSubmissionEndOffset == pPatch->DmaBufferPrivateDataSubmissionStartOffset)
1315 {
1316 /* this is a NOP, just return success */
1317// LOG(("null data size, treating as NOP"));
1318 return STATUS_SUCCESS;
1319 }
1320 else
1321 {
1322 WARN(("DmaBufferPrivateDataSubmissionEndOffset (%d) - DmaBufferPrivateDataSubmissionStartOffset (%d) < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR) (%d)",
1323 pPatch->DmaBufferPrivateDataSubmissionEndOffset,
1324 pPatch->DmaBufferPrivateDataSubmissionStartOffset,
1325 sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)));
1326 return STATUS_INVALID_PARAMETER;
1327 }
1328
1329 LOGF(("LEAVE, context(0x%x)", hAdapter));
1330
1331 return Status;
1332}
1333
1334NTSTATUS
1335APIENTRY
1336DxgkDdiSubmitCommandLegacy(
1337 CONST HANDLE hAdapter,
1338 CONST DXGKARG_SUBMITCOMMAND* pSubmitCommand)
1339{
1340 /* DxgkDdiSubmitCommand runs at dispatch, should not be pageable. */
1341 NTSTATUS Status = STATUS_SUCCESS;
1342
1343// LOGF(("ENTER, context(0x%x)", hAdapter));
1344
1345 vboxVDbgBreakFv();
1346
1347 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
1348 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pSubmitCommand->hContext;
1349 PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pPrivateDataBase = NULL;
1350 VBOXVDMACMD_TYPE enmCmd = VBOXVDMACMD_TYPE_UNDEFINED;
1351 Assert(pContext);
1352 Assert(pContext->pDevice);
1353 Assert(pContext->pDevice->pAdapter == pDevExt);
1354 Assert(!pSubmitCommand->DmaBufferSegmentId);
1355
1356 /* the DMA command buffer is located in system RAM, the host will need to pick it from there */
1357 //BufInfo.fFlags = 0; /* see VBOXVDMACBUF_FLAG_xx */
1358 if (pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset - pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))
1359 {
1360 pPrivateDataBase = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)((uint8_t*)pSubmitCommand->pDmaBufferPrivateData + pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset);
1361 Assert(pPrivateDataBase);
1362 enmCmd = pPrivateDataBase->enmCmd;
1363 }
1364 else if (pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset == pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset)
1365 {
1366 enmCmd = VBOXVDMACMD_TYPE_DMA_NOP;
1367 }
1368 else
1369 {
1370 WARN(("DmaBufferPrivateDataSubmissionEndOffset (%d) - DmaBufferPrivateDataSubmissionStartOffset (%d) < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR) (%d)",
1371 pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset,
1372 pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset,
1373 sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)));
1374 return STATUS_INVALID_PARAMETER;
1375 }
1376
1377 switch (enmCmd)
1378 {
1379 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
1380 {
1381 VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR *pPrivateData = (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR*)pPrivateDataBase;
1382 PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt = (PVBOXWDDM_DMA_PRIVATEDATA_BLT)pPrivateData;
1383 PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc;
1384 PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc;
1385 BOOLEAN fSrcChanged;
1386 BOOLEAN fDstChanged;
1387
1388 fDstChanged = vboxWddmAddrSetVram(&pDstAlloc->AllocData.Addr, pBlt->Blt.DstAlloc.segmentIdAlloc, pBlt->Blt.DstAlloc.offAlloc);
1389 fSrcChanged = vboxWddmAddrSetVram(&pSrcAlloc->AllocData.Addr, pBlt->Blt.SrcAlloc.segmentIdAlloc, pBlt->Blt.SrcAlloc.offAlloc);
1390
1391 if (VBOXWDDM_IS_FB_ALLOCATION(pDevExt, pDstAlloc))
1392 {
1393 Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS);
1394 }
1395
1396 Status = vboxVdmaProcessBltCmd(pDevExt, pContext, pBlt);
1397 if (!NT_SUCCESS(Status))
1398 WARN(("vboxVdmaProcessBltCmd failed, Status 0x%x", Status));
1399
1400 Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId,
1401 NT_SUCCESS(Status) ? DXGK_INTERRUPT_DMA_COMPLETED : DXGK_INTERRUPT_DMA_FAULTED);
1402 break;
1403 }
1404 case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP:
1405 {
1406 VBOXWDDM_DMA_PRIVATEDATA_FLIP *pFlip = (VBOXWDDM_DMA_PRIVATEDATA_FLIP*)pPrivateDataBase;
1407 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
1408 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
1409 vboxWddmAddrSetVram(&pAlloc->AllocData.Addr, pFlip->Flip.Alloc.segmentIdAlloc, pFlip->Flip.Alloc.offAlloc);
1410 vboxWddmAssignPrimary(pSource, pAlloc, pAlloc->AllocData.SurfDesc.VidPnSourceId);
1411 vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
1412
1413 Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId,
1414 NT_SUCCESS(Status) ? DXGK_INTERRUPT_DMA_COMPLETED : DXGK_INTERRUPT_DMA_FAULTED);
1415 break;
1416 }
1417 case VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL:
1418 {
1419 PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL pCF = (PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL)pPrivateDataBase;
1420 vboxWddmAddrSetVram(&pCF->ClrFill.Alloc.pAlloc->AllocData.Addr, pCF->ClrFill.Alloc.segmentIdAlloc, pCF->ClrFill.Alloc.offAlloc);
1421
1422 Status = vboxVdmaProcessClrFillCmd(pDevExt, pContext, pCF);
1423 if (!NT_SUCCESS(Status))
1424 WARN(("vboxVdmaProcessClrFillCmd failed, Status 0x%x", Status));
1425
1426 Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId,
1427 NT_SUCCESS(Status) ? DXGK_INTERRUPT_DMA_COMPLETED : DXGK_INTERRUPT_DMA_FAULTED);
1428 break;
1429 }
1430 case VBOXVDMACMD_TYPE_DMA_NOP:
1431 {
1432 Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, DXGK_INTERRUPT_DMA_COMPLETED);
1433 AssertNtStatusSuccess(Status);
1434 break;
1435 }
1436 default:
1437 {
1438 WARN(("unexpected command %d", enmCmd));
1439 break;
1440 }
1441 }
1442// LOGF(("LEAVE, context(0x%x)", hAdapter));
1443
1444 return Status;
1445}
1446
1447NTSTATUS
1448APIENTRY
1449DxgkDdiPreemptCommandLegacy(
1450 CONST HANDLE hAdapter,
1451 CONST DXGKARG_PREEMPTCOMMAND* pPreemptCommand)
1452{
1453 RT_NOREF(hAdapter, pPreemptCommand);
1454 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
1455
1456 AssertFailed();
1457 /** @todo fixme: implement */
1458
1459 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
1460
1461 return STATUS_SUCCESS;
1462}
1463
1464typedef struct VBOXWDDM_QUERYCURFENCE_CB
1465{
1466 PVBOXMP_DEVEXT pDevExt;
1467 ULONG MessageNumber;
1468 ULONG uLastCompletedCmdFenceId;
1469} VBOXWDDM_QUERYCURFENCE_CB, *PVBOXWDDM_QUERYCURFENCE_CB;
1470
1471static BOOLEAN vboxWddmQueryCurrentFenceCb(PVOID Context)
1472{
1473 PVBOXWDDM_QUERYCURFENCE_CB pdc = (PVBOXWDDM_QUERYCURFENCE_CB)Context;
1474 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1475 BOOL bRc = DxgkDdiInterruptRoutineLegacy(pDevExt, pdc->MessageNumber);
1476 pdc->uLastCompletedCmdFenceId = pDevExt->u.primary.uLastCompletedPagingBufferCmdFenceId;
1477 return bRc;
1478}
1479
1480NTSTATUS
1481APIENTRY
1482DxgkDdiQueryCurrentFenceLegacy(
1483 CONST HANDLE hAdapter,
1484 DXGKARG_QUERYCURRENTFENCE* pCurrentFence)
1485{
1486 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
1487
1488 vboxVDbgBreakF();
1489
1490 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
1491 VBOXWDDM_QUERYCURFENCE_CB context = {0};
1492 context.pDevExt = pDevExt;
1493 BOOLEAN bRet;
1494 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1495 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1496 vboxWddmQueryCurrentFenceCb,
1497 &context,
1498 0, /* IN ULONG MessageNumber */
1499 &bRet);
1500 AssertNtStatusSuccess(Status);
1501 if (Status == STATUS_SUCCESS)
1502 {
1503 pCurrentFence->CurrentFence = context.uLastCompletedCmdFenceId;
1504 }
1505
1506 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
1507
1508 return STATUS_SUCCESS;
1509}
1510
1511BOOLEAN DxgkDdiInterruptRoutineLegacy(
1512 IN CONST PVOID MiniportDeviceContext,
1513 IN ULONG MessageNumber
1514 )
1515{
1516 RT_NOREF(MessageNumber);
1517// LOGF(("ENTER, context(0x%p), msg(0x%x)", MiniportDeviceContext, MessageNumber));
1518
1519 vboxVDbgBreakFv();
1520
1521 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
1522 BOOLEAN bOur = FALSE;
1523 BOOLEAN bNeedDpc = FALSE;
1524 if (VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags) /* If HGSMI is enabled at all. */
1525 {
1526 VBOXVTLIST CtlList;
1527 vboxVtListInit(&CtlList);
1528
1529#ifdef VBOX_WITH_VIDEOHWACCEL
1530 VBOXVTLIST VhwaCmdList;
1531 vboxVtListInit(&VhwaCmdList);
1532#endif
1533
1534 uint32_t flags = VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags->u32HostFlags;
1535 bOur = (flags & HGSMIHOSTFLAGS_IRQ);
1536
1537 if (bOur)
1538 VBoxHGSMIClearIrq(&VBoxCommonFromDeviceExt(pDevExt)->hostCtx);
1539
1540 do
1541 {
1542 if (flags & HGSMIHOSTFLAGS_GCOMMAND_COMPLETED)
1543 {
1544 /* read the command offset */
1545 HGSMIOFFSET offCmd = VBVO_PORT_READ_U32(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port);
1546 Assert(offCmd != HGSMIOFFSET_VOID);
1547 if (offCmd != HGSMIOFFSET_VOID)
1548 {
1549 VBOXWDDM_HGSMICMD_TYPE enmType = vboxWddmHgsmiGetCmdTypeFromOffset(pDevExt, offCmd);
1550 PVBOXVTLIST pList;
1551 PVBOXSHGSMI pHeap;
1552 switch (enmType)
1553 {
1554 case VBOXWDDM_HGSMICMD_TYPE_CTL:
1555 pList = &CtlList;
1556 pHeap = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx;
1557 break;
1558 default:
1559 AssertBreakpoint();
1560 pList = NULL;
1561 pHeap = NULL;
1562 break;
1563 }
1564
1565 if (pHeap)
1566 {
1567 uint16_t chInfo;
1568 uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pvCmd =
1569 HGSMIBufferDataAndChInfoFromOffset(&pHeap->Heap.area, offCmd, &chInfo);
1570 Assert(pvCmd);
1571 if (pvCmd)
1572 {
1573 switch (chInfo)
1574 {
1575#ifdef VBOX_WITH_VIDEOHWACCEL
1576 case VBVA_VHWA_CMD:
1577 {
1578 vboxVhwaPutList(&VhwaCmdList, (VBOXVHWACMD*)pvCmd);
1579 break;
1580 }
1581#endif /* # ifdef VBOX_WITH_VIDEOHWACCEL */
1582 default:
1583 AssertBreakpoint();
1584 }
1585 }
1586 }
1587 }
1588 }
1589 else if (flags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
1590 {
1591 AssertBreakpoint();
1592 /** @todo FIXME: implement !!! */
1593 }
1594 else
1595 break;
1596
1597 flags = VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags->u32HostFlags;
1598 } while (1);
1599
1600 if (!vboxVtListIsEmpty(&CtlList))
1601 {
1602 vboxVtListCat(&pDevExt->CtlList, &CtlList);
1603 bNeedDpc = TRUE;
1604 }
1605#ifdef VBOX_WITH_VIDEOHWACCEL
1606 if (!vboxVtListIsEmpty(&VhwaCmdList))
1607 {
1608 vboxVtListCat(&pDevExt->VhwaCmdList, &VhwaCmdList);
1609 bNeedDpc = TRUE;
1610 }
1611#endif
1612
1613 if (pDevExt->bNotifyDxDpc)
1614 {
1615 bNeedDpc = TRUE;
1616 }
1617
1618 if (bOur)
1619 {
1620 if (flags & HGSMIHOSTFLAGS_VSYNC)
1621 {
1622 Assert(0);
1623 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1624 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1625 {
1626 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i];
1627 if (pTarget->fConnected)
1628 {
1629 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1630 notify.InterruptType = DXGK_INTERRUPT_CRTC_VSYNC;
1631 notify.CrtcVsync.VidPnTargetId = i;
1632 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1633 bNeedDpc = TRUE;
1634 }
1635 }
1636 }
1637
1638 if (pDevExt->bNotifyDxDpc)
1639 {
1640 bNeedDpc = TRUE;
1641 }
1642
1643#if 0 //def DEBUG_misha
1644 /* this is not entirely correct since host may concurrently complete some commands and raise a new IRQ while we are here,
1645 * still this allows to check that the host flags are correctly cleared after the ISR */
1646 Assert(VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags);
1647 uint32_t flags = VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags->u32HostFlags;
1648 Assert(flags == 0);
1649#endif
1650 }
1651
1652 if (bNeedDpc)
1653 {
1654 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1655 }
1656 }
1657
1658// LOGF(("LEAVE, context(0x%p), bOur(0x%x)", MiniportDeviceContext, (ULONG)bOur));
1659
1660 return bOur;
1661}
1662
1663
1664typedef struct VBOXWDDM_DPCDATA
1665{
1666 VBOXVTLIST CtlList;
1667#ifdef VBOX_WITH_VIDEOHWACCEL
1668 VBOXVTLIST VhwaCmdList;
1669#endif
1670 LIST_ENTRY CompletedDdiCmdQueue;
1671 BOOL bNotifyDpc;
1672} VBOXWDDM_DPCDATA, *PVBOXWDDM_DPCDATA;
1673
1674typedef struct VBOXWDDM_GETDPCDATA_CONTEXT
1675{
1676 PVBOXMP_DEVEXT pDevExt;
1677 VBOXWDDM_DPCDATA data;
1678} VBOXWDDM_GETDPCDATA_CONTEXT, *PVBOXWDDM_GETDPCDATA_CONTEXT;
1679
1680BOOLEAN vboxWddmGetDPCDataCallback(PVOID Context)
1681{
1682 PVBOXWDDM_GETDPCDATA_CONTEXT pdc = (PVBOXWDDM_GETDPCDATA_CONTEXT)Context;
1683 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1684 vboxVtListDetach2List(&pDevExt->CtlList, &pdc->data.CtlList);
1685#ifdef VBOX_WITH_VIDEOHWACCEL
1686 vboxVtListDetach2List(&pDevExt->VhwaCmdList, &pdc->data.VhwaCmdList);
1687#endif
1688
1689 pdc->data.bNotifyDpc = pDevExt->bNotifyDxDpc;
1690 pDevExt->bNotifyDxDpc = FALSE;
1691
1692 ASMAtomicWriteU32(&pDevExt->fCompletingCommands, 0);
1693
1694 return TRUE;
1695}
1696
1697VOID DxgkDdiDpcRoutineLegacy(
1698 IN CONST PVOID MiniportDeviceContext
1699 )
1700{
1701// LOGF(("ENTER, context(0x%p)", MiniportDeviceContext));
1702
1703 vboxVDbgBreakFv();
1704
1705 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
1706
1707 VBOXWDDM_GETDPCDATA_CONTEXT context = {0};
1708 BOOLEAN bRet;
1709
1710 context.pDevExt = pDevExt;
1711
1712 /* get DPC data at IRQL */
1713 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1714 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1715 vboxWddmGetDPCDataCallback,
1716 &context,
1717 0, /* IN ULONG MessageNumber */
1718 &bRet);
1719 AssertNtStatusSuccess(Status); NOREF(Status);
1720
1721 if (!vboxVtListIsEmpty(&context.data.CtlList))
1722 {
1723 int rc = VBoxSHGSMICommandPostprocessCompletion (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, &context.data.CtlList);
1724 AssertRC(rc);
1725 }
1726#ifdef VBOX_WITH_VIDEOHWACCEL
1727 if (!vboxVtListIsEmpty(&context.data.VhwaCmdList))
1728 {
1729 vboxVhwaCompletionListProcess(pDevExt, &context.data.VhwaCmdList);
1730 }
1731#endif
1732
1733// LOGF(("LEAVE, context(0x%p)", MiniportDeviceContext));
1734}
Note: See TracBrowser for help on using the repository browser.

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