VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use