VirtualBox

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

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

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.7 KB
Line 
1/* $Id: VBoxMPLegacy.cpp 85121 2020-07-08 19:33:26Z 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 BOOLEAN fVRAMUpdated = FALSE;
652 {
653 /* the allocations contain a real data in VRAM, do blitting */
654 vboxVdmaGgDmaBlt(pDevExt, &pBlt->Blt);
655 fVRAMUpdated = TRUE;
656
657 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId];
658 Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS);
659 Assert(pSource->pPrimaryAllocation == pDstAlloc);
660 vboxVdmaBltDirtyRectsUpdate(pDevExt, pSource, pBlt->Blt.DstRects.UpdateRects.cRects, pBlt->Blt.DstRects.UpdateRects.aRects);
661 }
662 return Status;
663}
664
665static NTSTATUS vboxVdmaProcessFlipCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_FLIP *pFlip)
666{
667 RT_NOREF(pContext);
668 NTSTATUS Status = STATUS_SUCCESS;
669 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
670 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
671 vboxWddmAssignPrimary(pSource, pAlloc, pAlloc->AllocData.SurfDesc.VidPnSourceId);
672 {
673 WARN(("unexpected flip request"));
674 }
675
676 return Status;
677}
678
679static NTSTATUS vboxVdmaProcessClrFillCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_CLRFILL *pCF)
680{
681 RT_NOREF(pContext);
682 NTSTATUS Status = STATUS_SUCCESS;
683// PVBOXWDDM_ALLOCATION pAlloc = pCF->ClrFill.Alloc.pAlloc;
684 {
685 Status = vboxVdmaGgDmaColorFill(pDevExt, &pCF->ClrFill);
686 if (!NT_SUCCESS(Status))
687 WARN(("vboxVdmaGgDmaColorFill failed Status 0x%x", Status));
688 }
689
690 return Status;
691}
692
693static void vboxWddmPatchLocationInit(D3DDDI_PATCHLOCATIONLIST *pPatchLocationListOut, UINT idx, UINT offPatch)
694{
695 memset(pPatchLocationListOut, 0, sizeof (*pPatchLocationListOut));
696 pPatchLocationListOut->AllocationIndex = idx;
697 pPatchLocationListOut->PatchOffset = offPatch;
698}
699
700static void vboxWddmPopulateDmaAllocInfo(PVBOXWDDM_DMA_ALLOCINFO pInfo, PVBOXWDDM_ALLOCATION pAlloc, DXGK_ALLOCATIONLIST *pDmaAlloc)
701{
702 pInfo->pAlloc = pAlloc;
703 if (pDmaAlloc->SegmentId)
704 {
705 pInfo->offAlloc = (VBOXVIDEOOFFSET)pDmaAlloc->PhysicalAddress.QuadPart;
706 pInfo->segmentIdAlloc = pDmaAlloc->SegmentId;
707 }
708 else
709 pInfo->segmentIdAlloc = 0;
710 pInfo->srcId = pAlloc->AllocData.SurfDesc.VidPnSourceId;
711}
712
713/*
714 *
715 * DxgkDdi
716 *
717 */
718
719NTSTATUS
720APIENTRY
721DxgkDdiBuildPagingBufferLegacy(
722 CONST HANDLE hAdapter,
723 DXGKARG_BUILDPAGINGBUFFER* pBuildPagingBuffer)
724{
725 /* DxgkDdiBuildPagingBuffer should be made pageable. */
726 PAGED_CODE();
727
728 vboxVDbgBreakFv();
729
730 NTSTATUS Status = STATUS_SUCCESS;
731 RT_NOREF(hAdapter);
732// PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
733
734 LOGF(("ENTER, context(0x%x)", hAdapter));
735
736 uint32_t cbCmdDma = 0;
737
738 /** @todo */
739 switch (pBuildPagingBuffer->Operation)
740 {
741 case DXGK_OPERATION_TRANSFER:
742 {
743 cbCmdDma = VBOXWDDM_DUMMY_DMABUFFER_SIZE;
744#ifdef VBOX_WITH_VDMA
745 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pBuildPagingBuffer->Transfer.hAllocation;
746 Assert(pAlloc);
747 if (pAlloc
748 && !pAlloc->fRcFlags.Overlay /* overlay surfaces actually contain a valid data */
749 && pAlloc->enmType != VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE /* shadow primary - also */
750 && pAlloc->enmType != VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER /* hgsmi buffer - also */
751 )
752 {
753 /* we do not care about the others for now */
754 Status = STATUS_SUCCESS;
755 break;
756 }
757 UINT cbCmd = VBOXVDMACMD_SIZE(VBOXVDMACMD_DMA_BPB_TRANSFER);
758 VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_HOST *pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbCmd);
759 Assert(pDr);
760 if (pDr)
761 {
762 SIZE_T cbTransfered = 0;
763 SIZE_T cbTransferSize = pBuildPagingBuffer->Transfer.TransferSize;
764 VBOXVDMACMD RT_UNTRUSTED_VOLATILE_HOST *pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
765 do
766 {
767 // vboxVdmaCBufDrCreate zero initializes the pDr
768 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
769 pDr->cbBuf = cbCmd;
770 pDr->rc = VERR_NOT_IMPLEMENTED;
771
772 pHdr->enmType = VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER;
773 pHdr->u32CmdSpecific = 0;
774 VBOXVDMACMD_DMA_BPB_TRANSFER RT_UNTRUSTED_VOLATILE_HOST *pBody
775 = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_DMA_BPB_TRANSFER);
776// pBody->cbTransferSize = (uint32_t)pBuildPagingBuffer->Transfer.TransferSize;
777 pBody->fFlags = 0;
778 SIZE_T cSrcPages = (cbTransferSize + 0xfff ) >> 12;
779 SIZE_T cDstPages = cSrcPages;
780
781 if (pBuildPagingBuffer->Transfer.Source.SegmentId)
782 {
783 uint64_t off = pBuildPagingBuffer->Transfer.Source.SegmentAddress.QuadPart;
784 off += pBuildPagingBuffer->Transfer.TransferOffset + cbTransfered;
785 pBody->Src.offVramBuf = off;
786 pBody->fFlags |= VBOXVDMACMD_DMA_BPB_TRANSFER_F_SRC_VRAMOFFSET;
787 }
788 else
789 {
790 UINT index = pBuildPagingBuffer->Transfer.MdlOffset + (UINT)(cbTransfered>>12);
791 pBody->Src.phBuf = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Source.pMdl)[index] << PAGE_SHIFT;
792 PFN_NUMBER num = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Source.pMdl)[index];
793 cSrcPages = 1;
794 for (UINT i = 1; i < ((cbTransferSize - cbTransfered + 0xfff) >> 12); ++i)
795 {
796 PFN_NUMBER cur = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Source.pMdl)[index+i];
797 if(cur != ++num)
798 {
799 cSrcPages+= i-1;
800 break;
801 }
802 }
803 }
804
805 if (pBuildPagingBuffer->Transfer.Destination.SegmentId)
806 {
807 uint64_t off = pBuildPagingBuffer->Transfer.Destination.SegmentAddress.QuadPart;
808 off += pBuildPagingBuffer->Transfer.TransferOffset;
809 pBody->Dst.offVramBuf = off + cbTransfered;
810 pBody->fFlags |= VBOXVDMACMD_DMA_BPB_TRANSFER_F_DST_VRAMOFFSET;
811 }
812 else
813 {
814 UINT index = pBuildPagingBuffer->Transfer.MdlOffset + (UINT)(cbTransfered>>12);
815 pBody->Dst.phBuf = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Destination.pMdl)[index] << PAGE_SHIFT;
816 PFN_NUMBER num = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Destination.pMdl)[index];
817 cDstPages = 1;
818 for (UINT i = 1; i < ((cbTransferSize - cbTransfered + 0xfff) >> 12); ++i)
819 {
820 PFN_NUMBER cur = MmGetMdlPfnArray(pBuildPagingBuffer->Transfer.Destination.pMdl)[index+i];
821 if(cur != ++num)
822 {
823 cDstPages+= i-1;
824 break;
825 }
826 }
827 }
828
829 SIZE_T cbCurTransfer;
830 cbCurTransfer = RT_MIN(cbTransferSize - cbTransfered, (SIZE_T)cSrcPages << PAGE_SHIFT);
831 cbCurTransfer = RT_MIN(cbCurTransfer, (SIZE_T)cDstPages << PAGE_SHIFT);
832
833 pBody->cbTransferSize = (UINT)cbCurTransfer;
834 Assert(!(cbCurTransfer & 0xfff));
835
836 int rc = vboxVdmaCBufDrSubmitSynch(pDevExt, &pDevExt->u.primary.Vdma, pDr);
837 AssertRC(rc);
838 if (RT_SUCCESS(rc))
839 {
840 Status = STATUS_SUCCESS;
841 cbTransfered += cbCurTransfer;
842 }
843 else
844 Status = STATUS_UNSUCCESSFUL;
845 } while (cbTransfered < cbTransferSize);
846 Assert(cbTransfered == cbTransferSize);
847 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
848 }
849 else
850 {
851 /** @todo try flushing.. */
852 LOGREL(("vboxVdmaCBufDrCreate returned NULL"));
853 Status = STATUS_INSUFFICIENT_RESOURCES;
854 }
855#endif /* #ifdef VBOX_WITH_VDMA */
856 break;
857 }
858 case DXGK_OPERATION_FILL:
859 {
860 cbCmdDma = VBOXWDDM_DUMMY_DMABUFFER_SIZE;
861 Assert(pBuildPagingBuffer->Fill.FillPattern == 0);
862 /*PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pBuildPagingBuffer->Fill.hAllocation; - unused. Incomplete code? */
863// pBuildPagingBuffer->pDmaBuffer = (uint8_t*)pBuildPagingBuffer->pDmaBuffer + VBOXVDMACMD_SIZE(VBOXVDMACMD_DMA_BPB_FILL);
864 break;
865 }
866 case DXGK_OPERATION_DISCARD_CONTENT:
867 {
868// AssertBreakpoint();
869 break;
870 }
871 default:
872 {
873 WARN(("unsupported op (%d)", pBuildPagingBuffer->Operation));
874 break;
875 }
876 }
877
878 if (cbCmdDma)
879 {
880 pBuildPagingBuffer->pDmaBuffer = ((uint8_t*)pBuildPagingBuffer->pDmaBuffer) + cbCmdDma;
881 }
882
883 LOGF(("LEAVE, context(0x%x)", hAdapter));
884
885 return Status;
886
887}
888
889/**
890 * DxgkDdiPresent
891 */
892NTSTATUS
893APIENTRY
894DxgkDdiPresentLegacy(
895 CONST HANDLE hContext,
896 DXGKARG_PRESENT *pPresent)
897{
898 RT_NOREF(hContext);
899 PAGED_CODE();
900
901// LOGF(("ENTER, hContext(0x%x)", hContext));
902
903 vboxVDbgBreakFv();
904
905 NTSTATUS Status = STATUS_SUCCESS;
906#ifdef VBOX_STRICT
907 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
908 PVBOXWDDM_DEVICE pDevice = pContext->pDevice;
909 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
910#endif
911
912 Assert(pPresent->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR));
913 if (pPresent->DmaBufferPrivateDataSize < sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR))
914 {
915 LOGREL(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR (%d)", pPresent->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)));
916 /** @todo can this actually happen? what status tu return? */
917 return STATUS_INVALID_PARAMETER;
918 }
919
920 PVBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR pPrivateData = (PVBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)pPresent->pDmaBufferPrivateData;
921 pPrivateData->BaseHdr.fFlags.Value = 0;
922 /*uint32_t cContexts2D = ASMAtomicReadU32(&pDevExt->cContexts2D); - unused */
923
924 if (pPresent->Flags.Blt)
925 {
926 Assert(pPresent->Flags.Value == 1); /* only Blt is set, we do not support anything else for now */
927 DXGK_ALLOCATIONLIST *pSrc = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX];
928 DXGK_ALLOCATIONLIST *pDst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX];
929 PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pSrc);
930 if (!pSrcAlloc)
931 {
932 /* this should not happen actually */
933 WARN(("failed to get Src Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation));
934 Status = STATUS_INVALID_HANDLE;
935 goto done;
936 }
937
938 PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDst);
939 if (!pDstAlloc)
940 {
941 /* this should not happen actually */
942 WARN(("failed to get Dst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation));
943 Status = STATUS_INVALID_HANDLE;
944 goto done;
945 }
946
947
948 UINT cbCmd = pPresent->DmaBufferPrivateDataSize;
949 pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_BLT;
950
951 PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt = (PVBOXWDDM_DMA_PRIVATEDATA_BLT)pPrivateData;
952
953 vboxWddmPopulateDmaAllocInfo(&pBlt->Blt.SrcAlloc, pSrcAlloc, pSrc);
954 vboxWddmPopulateDmaAllocInfo(&pBlt->Blt.DstAlloc, pDstAlloc, pDst);
955
956 ASSERT_WARN(!pSrcAlloc->fRcFlags.SharedResource, ("Shared Allocatoin used in Present!"));
957
958 pBlt->Blt.SrcRect = pPresent->SrcRect;
959 pBlt->Blt.DstRects.ContextRect = pPresent->DstRect;
960 pBlt->Blt.DstRects.UpdateRects.cRects = 0;
961 UINT cbHead = RT_UOFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_BLT, Blt.DstRects.UpdateRects.aRects[0]);
962 Assert(pPresent->SubRectCnt > pPresent->MultipassOffset);
963 UINT cbRects = (pPresent->SubRectCnt - pPresent->MultipassOffset) * sizeof (RECT);
964 pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE;
965 Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE);
966 cbCmd -= cbHead;
967 Assert(cbCmd < UINT32_MAX/2);
968 Assert(cbCmd > sizeof (RECT));
969 if (cbCmd >= cbRects)
970 {
971 cbCmd -= cbRects;
972 memcpy(&pBlt->Blt.DstRects.UpdateRects.aRects[0], &pPresent->pDstSubRects[pPresent->MultipassOffset], cbRects);
973 pBlt->Blt.DstRects.UpdateRects.cRects += cbRects/sizeof (RECT);
974
975 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbRects;
976 }
977 else
978 {
979 UINT cbFitingRects = (cbCmd/sizeof (RECT)) * sizeof (RECT);
980 Assert(cbFitingRects);
981 memcpy(&pBlt->Blt.DstRects.UpdateRects.aRects[0], &pPresent->pDstSubRects[pPresent->MultipassOffset], cbFitingRects);
982 cbCmd -= cbFitingRects;
983 pPresent->MultipassOffset += cbFitingRects/sizeof (RECT);
984 pBlt->Blt.DstRects.UpdateRects.cRects += cbFitingRects/sizeof (RECT);
985 Assert(pPresent->SubRectCnt > pPresent->MultipassOffset);
986
987 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbFitingRects;
988 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
989 }
990
991 memset(pPresent->pPatchLocationListOut, 0, 2*sizeof (D3DDDI_PATCHLOCATIONLIST));
992 pPresent->pPatchLocationListOut->PatchOffset = 0;
993 pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX;
994 ++pPresent->pPatchLocationListOut;
995 pPresent->pPatchLocationListOut->PatchOffset = 4;
996 pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX;
997 ++pPresent->pPatchLocationListOut;
998 }
999 else if (pPresent->Flags.Flip)
1000 {
1001 Assert(pPresent->Flags.Value == 4); /* only Blt is set, we do not support anything else for now */
1002 //Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D);
1003 DXGK_ALLOCATIONLIST *pSrc = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX];
1004 PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pSrc);
1005
1006 if (!pSrcAlloc)
1007 {
1008 /* this should not happen actually */
1009 WARN(("failed to get pSrc Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation));
1010 Status = STATUS_INVALID_HANDLE;
1011 goto done;
1012 }
1013
1014 Assert(pDevExt->cContexts3D);
1015 pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP;
1016 PVBOXWDDM_DMA_PRIVATEDATA_FLIP pFlip = (PVBOXWDDM_DMA_PRIVATEDATA_FLIP)pPrivateData;
1017
1018 vboxWddmPopulateDmaAllocInfo(&pFlip->Flip.Alloc, pSrcAlloc, pSrc);
1019
1020 UINT cbCmd = sizeof (VBOXWDDM_DMA_PRIVATEDATA_FLIP);
1021 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbCmd;
1022 pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE;
1023 Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE);
1024
1025 memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST));
1026 pPresent->pPatchLocationListOut->PatchOffset = 0;
1027 pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX;
1028 ++pPresent->pPatchLocationListOut;
1029 }
1030 else if (pPresent->Flags.ColorFill)
1031 {
1032 //Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_2D);
1033 Assert(pPresent->Flags.Value == 2); /* only ColorFill is set, we do not support anything else for now */
1034 DXGK_ALLOCATIONLIST *pDst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX];
1035 PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDst);
1036 if (!pDstAlloc)
1037 {
1038
1039 /* this should not happen actually */
1040 WARN(("failed to get pDst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation));
1041 Status = STATUS_INVALID_HANDLE;
1042 goto done;
1043 }
1044
1045 UINT cbCmd = pPresent->DmaBufferPrivateDataSize;
1046 pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL;
1047 PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL pCF = (PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL)pPrivateData;
1048
1049 vboxWddmPopulateDmaAllocInfo(&pCF->ClrFill.Alloc, pDstAlloc, pDst);
1050
1051 pCF->ClrFill.Color = pPresent->Color;
1052 pCF->ClrFill.Rects.cRects = 0;
1053 UINT cbHead = RT_UOFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_CLRFILL, ClrFill.Rects.aRects[0]);
1054 Assert(pPresent->SubRectCnt > pPresent->MultipassOffset);
1055 UINT cbRects = (pPresent->SubRectCnt - pPresent->MultipassOffset) * sizeof (RECT);
1056 pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE;
1057 Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE);
1058 cbCmd -= cbHead;
1059 Assert(cbCmd < UINT32_MAX/2);
1060 Assert(cbCmd > sizeof (RECT));
1061 if (cbCmd >= cbRects)
1062 {
1063 cbCmd -= cbRects;
1064 memcpy(&pCF->ClrFill.Rects.aRects[pPresent->MultipassOffset], pPresent->pDstSubRects, cbRects);
1065 pCF->ClrFill.Rects.cRects += cbRects/sizeof (RECT);
1066
1067 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbRects;
1068 }
1069 else
1070 {
1071 UINT cbFitingRects = (cbCmd/sizeof (RECT)) * sizeof (RECT);
1072 Assert(cbFitingRects);
1073 memcpy(&pCF->ClrFill.Rects.aRects[0], pPresent->pDstSubRects, cbFitingRects);
1074 cbCmd -= cbFitingRects;
1075 pPresent->MultipassOffset += cbFitingRects/sizeof (RECT);
1076 pCF->ClrFill.Rects.cRects += cbFitingRects/sizeof (RECT);
1077 Assert(pPresent->SubRectCnt > pPresent->MultipassOffset);
1078
1079 pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbFitingRects;
1080 Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER;
1081 }
1082
1083 memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST));
1084 pPresent->pPatchLocationListOut->PatchOffset = 0;
1085 pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX;
1086 ++pPresent->pPatchLocationListOut;
1087 }
1088 else
1089 {
1090 WARN(("cmd NOT IMPLEMENTED!! Flags(0x%x)", pPresent->Flags.Value));
1091 Status = STATUS_NOT_SUPPORTED;
1092 }
1093
1094done:
1095// LOGF(("LEAVE, hContext(0x%x), Status(0x%x)", hContext, Status));
1096
1097 return Status;
1098}
1099
1100NTSTATUS
1101APIENTRY
1102DxgkDdiRenderLegacy(
1103 CONST HANDLE hContext,
1104 DXGKARG_RENDER *pRender)
1105{
1106 RT_NOREF(hContext);
1107// LOGF(("ENTER, hContext(0x%x)", hContext));
1108
1109 if (pRender->DmaBufferPrivateDataSize < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))
1110 {
1111 WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_BASEHDR (%d)",
1112 pRender->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)));
1113 return STATUS_INVALID_PARAMETER;
1114 }
1115 if (pRender->CommandLength < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))
1116 {
1117 WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_BASEHDR (%d)",
1118 pRender->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)));
1119 return STATUS_INVALID_PARAMETER;
1120 }
1121 if (pRender->DmaSize < pRender->CommandLength)
1122 {
1123 WARN(("pRender->DmaSize(%d) < pRender->CommandLength(%d)",
1124 pRender->DmaSize, pRender->CommandLength));
1125 return STATUS_INVALID_PARAMETER;
1126 }
1127 if (pRender->PatchLocationListOutSize < pRender->PatchLocationListInSize)
1128 {
1129 WARN(("pRender->PatchLocationListOutSize(%d) < pRender->PatchLocationListInSize(%d)",
1130 pRender->PatchLocationListOutSize, pRender->PatchLocationListInSize));
1131 return STATUS_INVALID_PARAMETER;
1132 }
1133 if (pRender->AllocationListSize != pRender->PatchLocationListInSize)
1134 {
1135 WARN(("pRender->AllocationListSize(%d) != pRender->PatchLocationListInSize(%d)",
1136 pRender->AllocationListSize, pRender->PatchLocationListInSize));
1137 return STATUS_INVALID_PARAMETER;
1138 }
1139
1140 NTSTATUS Status = STATUS_SUCCESS;
1141
1142 __try
1143 {
1144 PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pInputHdr = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender->pCommand;
1145 switch (pInputHdr->enmCmd)
1146 {
1147 case VBOXVDMACMD_TYPE_DMA_NOP:
1148 {
1149 PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pPrivateData = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender->pDmaBufferPrivateData;
1150 pPrivateData->enmCmd = VBOXVDMACMD_TYPE_DMA_NOP;
1151 pRender->pDmaBufferPrivateData = (uint8_t*)pRender->pDmaBufferPrivateData + sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR);
1152 pRender->pDmaBuffer = ((uint8_t*)pRender->pDmaBuffer) + pRender->CommandLength;
1153 for (UINT i = 0; i < pRender->PatchLocationListInSize; ++i)
1154 {
1155 UINT offPatch = i * 4;
1156 if (offPatch + 4 > pRender->CommandLength)
1157 {
1158 WARN(("wrong offPatch"));
1159 return STATUS_INVALID_PARAMETER;
1160 }
1161 if (offPatch != pRender->pPatchLocationListIn[i].PatchOffset)
1162 {
1163 WARN(("wrong PatchOffset"));
1164 return STATUS_INVALID_PARAMETER;
1165 }
1166 if (i != pRender->pPatchLocationListIn[i].AllocationIndex)
1167 {
1168 WARN(("wrong AllocationIndex"));
1169 return STATUS_INVALID_PARAMETER;
1170 }
1171 vboxWddmPatchLocationInit(&pRender->pPatchLocationListOut[i], i, offPatch);
1172 }
1173 break;
1174 }
1175 default:
1176 {
1177 WARN(("unsupported command %d", pInputHdr->enmCmd));
1178 return STATUS_INVALID_PARAMETER;
1179 }
1180 }
1181 }
1182 __except (EXCEPTION_EXECUTE_HANDLER)
1183 {
1184 Status = STATUS_INVALID_PARAMETER;
1185 WARN(("invalid parameter"));
1186 }
1187// LOGF(("LEAVE, hContext(0x%x)", hContext));
1188
1189 return Status;
1190}
1191
1192NTSTATUS
1193APIENTRY
1194DxgkDdiPatchLegacy(
1195 CONST HANDLE hAdapter,
1196 CONST DXGKARG_PATCH* pPatch)
1197{
1198 RT_NOREF(hAdapter);
1199 /* DxgkDdiPatch should be made pageable. */
1200 PAGED_CODE();
1201
1202 NTSTATUS Status = STATUS_SUCCESS;
1203
1204 LOGF(("ENTER, context(0x%x)", hAdapter));
1205
1206 vboxVDbgBreakFv();
1207
1208 /* Value == 2 is Present
1209 * Value == 4 is RedirectedPresent
1210 * we do not expect any other flags to be set here */
1211// Assert(pPatch->Flags.Value == 2 || pPatch->Flags.Value == 4);
1212 if (pPatch->DmaBufferPrivateDataSubmissionEndOffset - pPatch->DmaBufferPrivateDataSubmissionStartOffset >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))
1213 {
1214 Assert(pPatch->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR));
1215 VBOXWDDM_DMA_PRIVATEDATA_BASEHDR *pPrivateDataBase = (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR*)((uint8_t*)pPatch->pDmaBufferPrivateData + pPatch->DmaBufferPrivateDataSubmissionStartOffset);
1216 switch (pPrivateDataBase->enmCmd)
1217 {
1218 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
1219 {
1220 PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt = (PVBOXWDDM_DMA_PRIVATEDATA_BLT)pPrivateDataBase;
1221 Assert(pPatch->PatchLocationListSubmissionLength == 2);
1222 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[pPatch->PatchLocationListSubmissionStart];
1223 Assert(pPatchList->AllocationIndex == DXGK_PRESENT_SOURCE_INDEX);
1224 Assert(pPatchList->PatchOffset == 0);
1225 const DXGK_ALLOCATIONLIST *pSrcAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1226 Assert(pSrcAllocationList->SegmentId);
1227 pBlt->Blt.SrcAlloc.segmentIdAlloc = pSrcAllocationList->SegmentId;
1228 pBlt->Blt.SrcAlloc.offAlloc = (VBOXVIDEOOFFSET)pSrcAllocationList->PhysicalAddress.QuadPart;
1229
1230 pPatchList = &pPatch->pPatchLocationList[pPatch->PatchLocationListSubmissionStart + 1];
1231 Assert(pPatchList->AllocationIndex == DXGK_PRESENT_DESTINATION_INDEX);
1232 Assert(pPatchList->PatchOffset == 4);
1233 const DXGK_ALLOCATIONLIST *pDstAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1234 Assert(pDstAllocationList->SegmentId);
1235 pBlt->Blt.DstAlloc.segmentIdAlloc = pDstAllocationList->SegmentId;
1236 pBlt->Blt.DstAlloc.offAlloc = (VBOXVIDEOOFFSET)pDstAllocationList->PhysicalAddress.QuadPart;
1237 break;
1238 }
1239 case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP:
1240 {
1241 PVBOXWDDM_DMA_PRIVATEDATA_FLIP pFlip = (PVBOXWDDM_DMA_PRIVATEDATA_FLIP)pPrivateDataBase;
1242 Assert(pPatch->PatchLocationListSubmissionLength == 1);
1243 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[pPatch->PatchLocationListSubmissionStart];
1244 Assert(pPatchList->AllocationIndex == DXGK_PRESENT_SOURCE_INDEX);
1245 Assert(pPatchList->PatchOffset == 0);
1246 const DXGK_ALLOCATIONLIST *pSrcAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1247 Assert(pSrcAllocationList->SegmentId);
1248 pFlip->Flip.Alloc.segmentIdAlloc = pSrcAllocationList->SegmentId;
1249 pFlip->Flip.Alloc.offAlloc = (VBOXVIDEOOFFSET)pSrcAllocationList->PhysicalAddress.QuadPart;
1250 break;
1251 }
1252 case VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL:
1253 {
1254 PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL pCF = (PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL)pPrivateDataBase;
1255 Assert(pPatch->PatchLocationListSubmissionLength == 1);
1256 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[pPatch->PatchLocationListSubmissionStart];
1257 Assert(pPatchList->AllocationIndex == DXGK_PRESENT_DESTINATION_INDEX);
1258 Assert(pPatchList->PatchOffset == 0);
1259 const DXGK_ALLOCATIONLIST *pDstAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1260 Assert(pDstAllocationList->SegmentId);
1261 pCF->ClrFill.Alloc.segmentIdAlloc = pDstAllocationList->SegmentId;
1262 pCF->ClrFill.Alloc.offAlloc = (VBOXVIDEOOFFSET)pDstAllocationList->PhysicalAddress.QuadPart;
1263 break;
1264 }
1265 case VBOXVDMACMD_TYPE_DMA_NOP:
1266 break;
1267 case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
1268 {
1269 uint8_t * pPrivateBuf = (uint8_t*)pPrivateDataBase;
1270 for (UINT i = pPatch->PatchLocationListSubmissionStart; i < pPatch->PatchLocationListSubmissionLength; ++i)
1271 {
1272 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[i];
1273 Assert(pPatchList->AllocationIndex < pPatch->AllocationListSize);
1274 const DXGK_ALLOCATIONLIST *pAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1275 Assert(pAllocationList->SegmentId);
1276 if (pAllocationList->SegmentId)
1277 {
1278 DXGK_ALLOCATIONLIST *pAllocation2Patch = (DXGK_ALLOCATIONLIST*)(pPrivateBuf + pPatchList->PatchOffset);
1279 pAllocation2Patch->SegmentId = pAllocationList->SegmentId;
1280 pAllocation2Patch->PhysicalAddress.QuadPart = pAllocationList->PhysicalAddress.QuadPart + pPatchList->AllocationOffset;
1281 Assert(!(pAllocationList->PhysicalAddress.QuadPart & 0xfffUL)); /* <- just a check to ensure allocation offset does not go here */
1282 }
1283 }
1284 break;
1285 }
1286 default:
1287 {
1288 AssertBreakpoint();
1289 uint8_t *pBuf = ((uint8_t *)pPatch->pDmaBuffer) + pPatch->DmaBufferSubmissionStartOffset;
1290 for (UINT i = pPatch->PatchLocationListSubmissionStart; i < pPatch->PatchLocationListSubmissionLength; ++i)
1291 {
1292 const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[i];
1293 Assert(pPatchList->AllocationIndex < pPatch->AllocationListSize);
1294 const DXGK_ALLOCATIONLIST *pAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex];
1295 if (pAllocationList->SegmentId)
1296 {
1297 Assert(pPatchList->PatchOffset < (pPatch->DmaBufferSubmissionEndOffset - pPatch->DmaBufferSubmissionStartOffset));
1298 *((VBOXVIDEOOFFSET*)(pBuf+pPatchList->PatchOffset)) = (VBOXVIDEOOFFSET)pAllocationList->PhysicalAddress.QuadPart;
1299 }
1300 else
1301 {
1302 /* sanity */
1303 if (pPatch->Flags.Value == 2 || pPatch->Flags.Value == 4)
1304 Assert(i == 0);
1305 }
1306 }
1307 break;
1308 }
1309 }
1310 }
1311 else if (pPatch->DmaBufferPrivateDataSubmissionEndOffset == pPatch->DmaBufferPrivateDataSubmissionStartOffset)
1312 {
1313 /* this is a NOP, just return success */
1314// LOG(("null data size, treating as NOP"));
1315 return STATUS_SUCCESS;
1316 }
1317 else
1318 {
1319 WARN(("DmaBufferPrivateDataSubmissionEndOffset (%d) - DmaBufferPrivateDataSubmissionStartOffset (%d) < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR) (%d)",
1320 pPatch->DmaBufferPrivateDataSubmissionEndOffset,
1321 pPatch->DmaBufferPrivateDataSubmissionStartOffset,
1322 sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)));
1323 return STATUS_INVALID_PARAMETER;
1324 }
1325
1326 LOGF(("LEAVE, context(0x%x)", hAdapter));
1327
1328 return Status;
1329}
1330
1331NTSTATUS
1332APIENTRY
1333DxgkDdiSubmitCommandLegacy(
1334 CONST HANDLE hAdapter,
1335 CONST DXGKARG_SUBMITCOMMAND* pSubmitCommand)
1336{
1337 /* DxgkDdiSubmitCommand runs at dispatch, should not be pageable. */
1338 NTSTATUS Status = STATUS_SUCCESS;
1339
1340// LOGF(("ENTER, context(0x%x)", hAdapter));
1341
1342 vboxVDbgBreakFv();
1343
1344 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
1345 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pSubmitCommand->hContext;
1346 PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pPrivateDataBase = NULL;
1347 VBOXVDMACMD_TYPE enmCmd = VBOXVDMACMD_TYPE_UNDEFINED;
1348 Assert(pContext);
1349 Assert(pContext->pDevice);
1350 Assert(pContext->pDevice->pAdapter == pDevExt);
1351 Assert(!pSubmitCommand->DmaBufferSegmentId);
1352
1353 /* the DMA command buffer is located in system RAM, the host will need to pick it from there */
1354 //BufInfo.fFlags = 0; /* see VBOXVDMACBUF_FLAG_xx */
1355 if (pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset - pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))
1356 {
1357 pPrivateDataBase = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)((uint8_t*)pSubmitCommand->pDmaBufferPrivateData + pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset);
1358 Assert(pPrivateDataBase);
1359 enmCmd = pPrivateDataBase->enmCmd;
1360 }
1361 else if (pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset == pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset)
1362 {
1363 enmCmd = VBOXVDMACMD_TYPE_DMA_NOP;
1364 }
1365 else
1366 {
1367 WARN(("DmaBufferPrivateDataSubmissionEndOffset (%d) - DmaBufferPrivateDataSubmissionStartOffset (%d) < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR) (%d)",
1368 pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset,
1369 pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset,
1370 sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)));
1371 return STATUS_INVALID_PARAMETER;
1372 }
1373
1374 switch (enmCmd)
1375 {
1376 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
1377 {
1378 VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR *pPrivateData = (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR*)pPrivateDataBase;
1379 PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt = (PVBOXWDDM_DMA_PRIVATEDATA_BLT)pPrivateData;
1380 PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc;
1381 PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc;
1382 BOOLEAN fSrcChanged;
1383 BOOLEAN fDstChanged;
1384
1385 fDstChanged = vboxWddmAddrSetVram(&pDstAlloc->AllocData.Addr, pBlt->Blt.DstAlloc.segmentIdAlloc, pBlt->Blt.DstAlloc.offAlloc);
1386 fSrcChanged = vboxWddmAddrSetVram(&pSrcAlloc->AllocData.Addr, pBlt->Blt.SrcAlloc.segmentIdAlloc, pBlt->Blt.SrcAlloc.offAlloc);
1387
1388 if (VBOXWDDM_IS_FB_ALLOCATION(pDevExt, pDstAlloc))
1389 {
1390 Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS);
1391 }
1392
1393 Status = vboxVdmaProcessBltCmd(pDevExt, pContext, pBlt);
1394 if (!NT_SUCCESS(Status))
1395 WARN(("vboxVdmaProcessBltCmd failed, Status 0x%x", Status));
1396
1397 Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId,
1398 NT_SUCCESS(Status) ? DXGK_INTERRUPT_DMA_COMPLETED : DXGK_INTERRUPT_DMA_FAULTED);
1399 break;
1400 }
1401 case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP:
1402 {
1403 VBOXWDDM_DMA_PRIVATEDATA_FLIP *pFlip = (VBOXWDDM_DMA_PRIVATEDATA_FLIP*)pPrivateDataBase;
1404 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
1405 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
1406 vboxWddmAddrSetVram(&pAlloc->AllocData.Addr, pFlip->Flip.Alloc.segmentIdAlloc, pFlip->Flip.Alloc.offAlloc);
1407 vboxWddmAssignPrimary(pSource, pAlloc, pAlloc->AllocData.SurfDesc.VidPnSourceId);
1408 vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
1409
1410 Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId,
1411 NT_SUCCESS(Status) ? DXGK_INTERRUPT_DMA_COMPLETED : DXGK_INTERRUPT_DMA_FAULTED);
1412 break;
1413 }
1414 case VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL:
1415 {
1416 PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL pCF = (PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL)pPrivateDataBase;
1417 vboxWddmAddrSetVram(&pCF->ClrFill.Alloc.pAlloc->AllocData.Addr, pCF->ClrFill.Alloc.segmentIdAlloc, pCF->ClrFill.Alloc.offAlloc);
1418
1419 Status = vboxVdmaProcessClrFillCmd(pDevExt, pContext, pCF);
1420 if (!NT_SUCCESS(Status))
1421 WARN(("vboxVdmaProcessClrFillCmd failed, Status 0x%x", Status));
1422
1423 Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId,
1424 NT_SUCCESS(Status) ? DXGK_INTERRUPT_DMA_COMPLETED : DXGK_INTERRUPT_DMA_FAULTED);
1425 break;
1426 }
1427 case VBOXVDMACMD_TYPE_DMA_NOP:
1428 {
1429 Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, DXGK_INTERRUPT_DMA_COMPLETED);
1430 AssertNtStatusSuccess(Status);
1431 break;
1432 }
1433 default:
1434 {
1435 WARN(("unexpected command %d", enmCmd));
1436 break;
1437 }
1438 }
1439// LOGF(("LEAVE, context(0x%x)", hAdapter));
1440
1441 return Status;
1442}
1443
1444NTSTATUS
1445APIENTRY
1446DxgkDdiPreemptCommandLegacy(
1447 CONST HANDLE hAdapter,
1448 CONST DXGKARG_PREEMPTCOMMAND* pPreemptCommand)
1449{
1450 RT_NOREF(hAdapter, pPreemptCommand);
1451 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
1452
1453 AssertFailed();
1454 /** @todo fixme: implement */
1455
1456 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
1457
1458 return STATUS_SUCCESS;
1459}
1460
1461typedef struct VBOXWDDM_QUERYCURFENCE_CB
1462{
1463 PVBOXMP_DEVEXT pDevExt;
1464 ULONG MessageNumber;
1465 ULONG uLastCompletedCmdFenceId;
1466} VBOXWDDM_QUERYCURFENCE_CB, *PVBOXWDDM_QUERYCURFENCE_CB;
1467
1468static BOOLEAN vboxWddmQueryCurrentFenceCb(PVOID Context)
1469{
1470 PVBOXWDDM_QUERYCURFENCE_CB pdc = (PVBOXWDDM_QUERYCURFENCE_CB)Context;
1471 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1472 BOOL bRc = DxgkDdiInterruptRoutineLegacy(pDevExt, pdc->MessageNumber);
1473 pdc->uLastCompletedCmdFenceId = pDevExt->u.primary.uLastCompletedPagingBufferCmdFenceId;
1474 return bRc;
1475}
1476
1477NTSTATUS
1478APIENTRY
1479DxgkDdiQueryCurrentFenceLegacy(
1480 CONST HANDLE hAdapter,
1481 DXGKARG_QUERYCURRENTFENCE* pCurrentFence)
1482{
1483 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
1484
1485 vboxVDbgBreakF();
1486
1487 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
1488 VBOXWDDM_QUERYCURFENCE_CB context = {0};
1489 context.pDevExt = pDevExt;
1490 BOOLEAN bRet;
1491 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1492 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1493 vboxWddmQueryCurrentFenceCb,
1494 &context,
1495 0, /* IN ULONG MessageNumber */
1496 &bRet);
1497 AssertNtStatusSuccess(Status);
1498 if (Status == STATUS_SUCCESS)
1499 {
1500 pCurrentFence->CurrentFence = context.uLastCompletedCmdFenceId;
1501 }
1502
1503 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
1504
1505 return STATUS_SUCCESS;
1506}
1507
1508BOOLEAN DxgkDdiInterruptRoutineLegacy(
1509 IN CONST PVOID MiniportDeviceContext,
1510 IN ULONG MessageNumber
1511 )
1512{
1513 RT_NOREF(MessageNumber);
1514// LOGF(("ENTER, context(0x%p), msg(0x%x)", MiniportDeviceContext, MessageNumber));
1515
1516 vboxVDbgBreakFv();
1517
1518 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
1519 BOOLEAN bOur = FALSE;
1520 BOOLEAN bNeedDpc = FALSE;
1521 if (VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags) /* If HGSMI is enabled at all. */
1522 {
1523 VBOXVTLIST CtlList;
1524 vboxVtListInit(&CtlList);
1525
1526#ifdef VBOX_WITH_VIDEOHWACCEL
1527 VBOXVTLIST VhwaCmdList;
1528 vboxVtListInit(&VhwaCmdList);
1529#endif
1530
1531 uint32_t flags = VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags->u32HostFlags;
1532 bOur = (flags & HGSMIHOSTFLAGS_IRQ);
1533
1534 if (bOur)
1535 VBoxHGSMIClearIrq(&VBoxCommonFromDeviceExt(pDevExt)->hostCtx);
1536
1537 do
1538 {
1539 if (flags & HGSMIHOSTFLAGS_GCOMMAND_COMPLETED)
1540 {
1541 /* read the command offset */
1542 HGSMIOFFSET offCmd = VBVO_PORT_READ_U32(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port);
1543 Assert(offCmd != HGSMIOFFSET_VOID);
1544 if (offCmd != HGSMIOFFSET_VOID)
1545 {
1546 VBOXWDDM_HGSMICMD_TYPE enmType = vboxWddmHgsmiGetCmdTypeFromOffset(pDevExt, offCmd);
1547 PVBOXVTLIST pList;
1548 PVBOXSHGSMI pHeap;
1549 switch (enmType)
1550 {
1551 case VBOXWDDM_HGSMICMD_TYPE_CTL:
1552 pList = &CtlList;
1553 pHeap = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx;
1554 break;
1555 default:
1556 AssertBreakpoint();
1557 pList = NULL;
1558 pHeap = NULL;
1559 break;
1560 }
1561
1562 if (pHeap)
1563 {
1564 uint16_t chInfo;
1565 uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pvCmd =
1566 HGSMIBufferDataAndChInfoFromOffset(&pHeap->Heap.area, offCmd, &chInfo);
1567 Assert(pvCmd);
1568 if (pvCmd)
1569 {
1570 switch (chInfo)
1571 {
1572#ifdef VBOX_WITH_VIDEOHWACCEL
1573 case VBVA_VHWA_CMD:
1574 {
1575 vboxVhwaPutList(&VhwaCmdList, (VBOXVHWACMD*)pvCmd);
1576 break;
1577 }
1578#endif /* # ifdef VBOX_WITH_VIDEOHWACCEL */
1579 default:
1580 AssertBreakpoint();
1581 }
1582 }
1583 }
1584 }
1585 }
1586 else if (flags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
1587 {
1588 AssertBreakpoint();
1589 /** @todo FIXME: implement !!! */
1590 }
1591 else
1592 break;
1593
1594 flags = VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags->u32HostFlags;
1595 } while (1);
1596
1597 if (!vboxVtListIsEmpty(&CtlList))
1598 {
1599 vboxVtListCat(&pDevExt->CtlList, &CtlList);
1600 bNeedDpc = TRUE;
1601 }
1602#ifdef VBOX_WITH_VIDEOHWACCEL
1603 if (!vboxVtListIsEmpty(&VhwaCmdList))
1604 {
1605 vboxVtListCat(&pDevExt->VhwaCmdList, &VhwaCmdList);
1606 bNeedDpc = TRUE;
1607 }
1608#endif
1609
1610 if (pDevExt->bNotifyDxDpc)
1611 {
1612 bNeedDpc = TRUE;
1613 }
1614
1615 if (bOur)
1616 {
1617 if (flags & HGSMIHOSTFLAGS_VSYNC)
1618 {
1619 Assert(0);
1620 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1621 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1622 {
1623 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i];
1624 if (pTarget->fConnected)
1625 {
1626 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1627 notify.InterruptType = DXGK_INTERRUPT_CRTC_VSYNC;
1628 notify.CrtcVsync.VidPnTargetId = i;
1629 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1630 bNeedDpc = TRUE;
1631 }
1632 }
1633 }
1634
1635 if (pDevExt->bNotifyDxDpc)
1636 {
1637 bNeedDpc = TRUE;
1638 }
1639
1640#if 0 //def DEBUG_misha
1641 /* this is not entirely correct since host may concurrently complete some commands and raise a new IRQ while we are here,
1642 * still this allows to check that the host flags are correctly cleared after the ISR */
1643 Assert(VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags);
1644 uint32_t flags = VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags->u32HostFlags;
1645 Assert(flags == 0);
1646#endif
1647 }
1648
1649 if (bNeedDpc)
1650 {
1651 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1652 }
1653 }
1654
1655// LOGF(("LEAVE, context(0x%p), bOur(0x%x)", MiniportDeviceContext, (ULONG)bOur));
1656
1657 return bOur;
1658}
1659
1660
1661typedef struct VBOXWDDM_DPCDATA
1662{
1663 VBOXVTLIST CtlList;
1664#ifdef VBOX_WITH_VIDEOHWACCEL
1665 VBOXVTLIST VhwaCmdList;
1666#endif
1667 LIST_ENTRY CompletedDdiCmdQueue;
1668 BOOL bNotifyDpc;
1669} VBOXWDDM_DPCDATA, *PVBOXWDDM_DPCDATA;
1670
1671typedef struct VBOXWDDM_GETDPCDATA_CONTEXT
1672{
1673 PVBOXMP_DEVEXT pDevExt;
1674 VBOXWDDM_DPCDATA data;
1675} VBOXWDDM_GETDPCDATA_CONTEXT, *PVBOXWDDM_GETDPCDATA_CONTEXT;
1676
1677BOOLEAN vboxWddmGetDPCDataCallback(PVOID Context)
1678{
1679 PVBOXWDDM_GETDPCDATA_CONTEXT pdc = (PVBOXWDDM_GETDPCDATA_CONTEXT)Context;
1680 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1681 vboxVtListDetach2List(&pDevExt->CtlList, &pdc->data.CtlList);
1682#ifdef VBOX_WITH_VIDEOHWACCEL
1683 vboxVtListDetach2List(&pDevExt->VhwaCmdList, &pdc->data.VhwaCmdList);
1684#endif
1685
1686 pdc->data.bNotifyDpc = pDevExt->bNotifyDxDpc;
1687 pDevExt->bNotifyDxDpc = FALSE;
1688
1689 ASMAtomicWriteU32(&pDevExt->fCompletingCommands, 0);
1690
1691 return TRUE;
1692}
1693
1694VOID DxgkDdiDpcRoutineLegacy(
1695 IN CONST PVOID MiniportDeviceContext
1696 )
1697{
1698// LOGF(("ENTER, context(0x%p)", MiniportDeviceContext));
1699
1700 vboxVDbgBreakFv();
1701
1702 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
1703
1704 VBOXWDDM_GETDPCDATA_CONTEXT context = {0};
1705 BOOLEAN bRet;
1706
1707 context.pDevExt = pDevExt;
1708
1709 /* get DPC data at IRQL */
1710 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1711 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1712 vboxWddmGetDPCDataCallback,
1713 &context,
1714 0, /* IN ULONG MessageNumber */
1715 &bRet);
1716 AssertNtStatusSuccess(Status); NOREF(Status);
1717
1718 if (!vboxVtListIsEmpty(&context.data.CtlList))
1719 {
1720 int rc = VBoxSHGSMICommandPostprocessCompletion (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, &context.data.CtlList);
1721 AssertRC(rc);
1722 }
1723#ifdef VBOX_WITH_VIDEOHWACCEL
1724 if (!vboxVtListIsEmpty(&context.data.VhwaCmdList))
1725 {
1726 vboxVhwaCompletionListProcess(pDevExt, &context.data.VhwaCmdList);
1727 }
1728#endif
1729
1730// LOGF(("LEAVE, context(0x%p)", MiniportDeviceContext));
1731}
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