VirtualBox

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

Last change on this file since 95191 was 95191, checked in by vboxsync, 3 years ago

WDDM: render should output all patch locations; when allocation is deleted then detach it from VidPN source if necessary. bugref:9845

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 192.7 KB
Line 
1/* $Id: VBoxMPWddm.cpp 95191 2022-06-03 18:49:41Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver
4 */
5
6/*
7 * Copyright (C) 2011-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "VBoxMPWddm.h"
19#include "common/VBoxMPCommon.h"
20#include "common/VBoxMPHGSMI.h"
21#ifdef VBOX_WITH_VIDEOHWACCEL
22# include "VBoxMPVhwa.h"
23#endif
24#include "VBoxMPVidPn.h"
25#include "VBoxMPLegacy.h"
26
27#include <iprt/alloc.h>
28#include <iprt/asm.h>
29#include <iprt/param.h>
30#include <iprt/initterm.h>
31#include <iprt/utf16.h>
32#include <iprt/x86.h>
33
34#include <VBox/VBoxGuestLib.h>
35#include <VBox/VMMDev.h> /* for VMMDevVideoSetVisibleRegion */
36#include <VBoxVideo.h>
37#include <wingdi.h> /* needed for RGNDATA definition */
38#include <VBoxDisplay.h> /* this is from Additions/WINNT/include/ to include escape codes */
39#include <VBoxVideoVBE.h>
40#include <VBox/Version.h>
41
42#ifdef VBOX_WITH_VMSVGA
43#include "gallium/VBoxMPGaWddm.h"
44#endif
45
46#ifdef DEBUG
47DWORD g_VBoxLogUm = VBOXWDDM_CFG_LOG_UM_BACKDOOR;
48#else
49DWORD g_VBoxLogUm = 0;
50#endif
51DWORD g_RefreshRate = 0;
52
53/* Whether the driver is display-only (no 3D) for Windows 8 or newer guests. */
54DWORD g_VBoxDisplayOnly = 0;
55
56#define VBOXWDDM_MEMTAG 'MDBV'
57PVOID vboxWddmMemAlloc(IN SIZE_T cbSize)
58{
59 POOL_TYPE enmPoolType = (VBoxQueryWinVersion(NULL) >= WINVERSION_8) ? NonPagedPoolNx : NonPagedPool;
60 return ExAllocatePoolWithTag(enmPoolType, cbSize, VBOXWDDM_MEMTAG);
61}
62
63PVOID vboxWddmMemAllocZero(IN SIZE_T cbSize)
64{
65 PVOID pvMem = vboxWddmMemAlloc(cbSize);
66 if (pvMem)
67 memset(pvMem, 0, cbSize);
68 return pvMem;
69}
70
71
72VOID vboxWddmMemFree(PVOID pvMem)
73{
74 ExFreePool(pvMem);
75}
76
77DECLINLINE(void) VBoxWddmOaHostIDReleaseLocked(PVBOXWDDM_OPENALLOCATION pOa)
78{
79 Assert(pOa->cHostIDRefs);
80 PVBOXWDDM_ALLOCATION pAllocation = pOa->pAllocation;
81 Assert(pAllocation->AllocData.cHostIDRefs >= pOa->cHostIDRefs);
82 Assert(pAllocation->AllocData.hostID);
83 --pOa->cHostIDRefs;
84 --pAllocation->AllocData.cHostIDRefs;
85 if (!pAllocation->AllocData.cHostIDRefs)
86 pAllocation->AllocData.hostID = 0;
87}
88
89DECLINLINE(void) VBoxWddmOaHostIDCheckReleaseLocked(PVBOXWDDM_OPENALLOCATION pOa)
90{
91 if (pOa->cHostIDRefs)
92 VBoxWddmOaHostIDReleaseLocked(pOa);
93}
94
95DECLINLINE(void) VBoxWddmOaRelease(PVBOXWDDM_OPENALLOCATION pOa)
96{
97 PVBOXWDDM_ALLOCATION pAllocation = pOa->pAllocation;
98 KIRQL OldIrql;
99 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
100 Assert(pAllocation->cOpens);
101 VBoxWddmOaHostIDCheckReleaseLocked(pOa);
102 --pAllocation->cOpens;
103 uint32_t cOpens = --pOa->cOpens;
104 Assert(cOpens < UINT32_MAX/2);
105 if (!cOpens)
106 {
107 RemoveEntryList(&pOa->ListEntry);
108 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
109 vboxWddmMemFree(pOa);
110 }
111 else
112 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
113}
114
115DECLINLINE(PVBOXWDDM_OPENALLOCATION) VBoxWddmOaSearchLocked(PVBOXWDDM_DEVICE pDevice, PVBOXWDDM_ALLOCATION pAllocation)
116{
117 for (PLIST_ENTRY pCur = pAllocation->OpenList.Flink; pCur != &pAllocation->OpenList; pCur = pCur->Flink)
118 {
119 PVBOXWDDM_OPENALLOCATION pCurOa = CONTAINING_RECORD(pCur, VBOXWDDM_OPENALLOCATION, ListEntry);
120 if (pCurOa->pDevice == pDevice)
121 {
122 return pCurOa;
123 }
124 }
125 return NULL;
126}
127
128DECLINLINE(PVBOXWDDM_OPENALLOCATION) VBoxWddmOaSearch(PVBOXWDDM_DEVICE pDevice, PVBOXWDDM_ALLOCATION pAllocation)
129{
130 PVBOXWDDM_OPENALLOCATION pOa;
131 KIRQL OldIrql;
132 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
133 pOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
134 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
135 return pOa;
136}
137
138DECLINLINE(int) VBoxWddmOaSetHostID(PVBOXWDDM_DEVICE pDevice, PVBOXWDDM_ALLOCATION pAllocation, uint32_t hostID, uint32_t *pHostID)
139{
140 PVBOXWDDM_OPENALLOCATION pOa;
141 KIRQL OldIrql;
142 int rc = VINF_SUCCESS;
143 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
144 pOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
145 if (!pOa)
146 {
147 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);;
148 WARN(("no open allocation!"));
149 return VERR_INVALID_STATE;
150 }
151
152 if (hostID)
153 {
154 if (pAllocation->AllocData.hostID == 0)
155 {
156 pAllocation->AllocData.hostID = hostID;
157 }
158 else if (pAllocation->AllocData.hostID != hostID)
159 {
160 WARN(("hostID differ: alloc(%d), trying to assign(%d)", pAllocation->AllocData.hostID, hostID));
161 hostID = pAllocation->AllocData.hostID;
162 rc = VERR_NOT_EQUAL;
163 }
164
165 ++pAllocation->AllocData.cHostIDRefs;
166 ++pOa->cHostIDRefs;
167 }
168 else
169 VBoxWddmOaHostIDCheckReleaseLocked(pOa);
170
171 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
172
173 if (pHostID)
174 *pHostID = hostID;
175
176 return rc;
177}
178
179DECLINLINE(PVBOXWDDM_ALLOCATION) vboxWddmGetAllocationFromHandle(PVBOXMP_DEVEXT pDevExt, D3DKMT_HANDLE hAllocation)
180{
181 DXGKARGCB_GETHANDLEDATA GhData;
182 GhData.hObject = hAllocation;
183 GhData.Type = DXGK_HANDLE_ALLOCATION;
184 GhData.Flags.Value = 0;
185 return (PVBOXWDDM_ALLOCATION)pDevExt->u.primary.DxgkInterface.DxgkCbGetHandleData(&GhData);
186}
187
188int vboxWddmGhDisplayPostInfoScreen(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData, const POINT * pVScreenPos, uint16_t fFlags)
189{
190 VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_HOST *pScreen =
191 (VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_HOST *)VBoxHGSMIBufferAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx,
192 sizeof(VBVAINFOSCREEN),
193 HGSMI_CH_VBVA,
194 VBVA_INFO_SCREEN);
195 if (!pScreen != NULL)
196 {
197 WARN(("VBoxHGSMIBufferAlloc failed"));
198 return VERR_OUT_OF_RESOURCES;
199 }
200
201 int rc = vboxWddmScreenInfoInit(pScreen, pAllocData, pVScreenPos, fFlags);
202 if (RT_SUCCESS(rc))
203 {
204 pScreen->u32StartOffset = 0; //(uint32_t)offVram; /* we pretend the view is located at the start of each framebuffer */
205
206 rc = VBoxHGSMIBufferSubmit(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pScreen);
207 if (RT_FAILURE(rc))
208 WARN(("VBoxHGSMIBufferSubmit failed %d", rc));
209 }
210 else
211 WARN(("VBoxHGSMIBufferSubmit failed %d", rc));
212
213 VBoxHGSMIBufferFree(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pScreen);
214
215 return rc;
216}
217
218int vboxWddmGhDisplayPostInfoView(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData)
219{
220 VBOXVIDEOOFFSET offVram = vboxWddmAddrFramOffset(&pAllocData->Addr);
221 if (offVram == VBOXVIDEOOFFSET_VOID)
222 {
223 WARN(("offVram == VBOXVIDEOOFFSET_VOID"));
224 return VERR_INVALID_PARAMETER;
225 }
226
227 /* Issue the screen info command. */
228 VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_HOST *pView =
229 (VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_HOST *)VBoxHGSMIBufferAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx,
230 sizeof(VBVAINFOVIEW), HGSMI_CH_VBVA, VBVA_INFO_VIEW);
231 if (!pView)
232 {
233 WARN(("VBoxHGSMIBufferAlloc failed"));
234 return VERR_OUT_OF_RESOURCES;
235 }
236 pView->u32ViewIndex = pAllocData->SurfDesc.VidPnSourceId;
237 pView->u32ViewOffset = (uint32_t)offVram; /* we pretend the view is located at the start of each framebuffer */
238 pView->u32ViewSize = vboxWddmVramCpuVisibleSegmentSize(pDevExt)/VBoxCommonFromDeviceExt(pDevExt)->cDisplays;
239 pView->u32MaxScreenSize = pView->u32ViewSize;
240
241 int rc = VBoxHGSMIBufferSubmit (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pView);
242 if (RT_FAILURE(rc))
243 WARN(("VBoxHGSMIBufferSubmit failed %d", rc));
244
245 VBoxHGSMIBufferFree(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pView);
246 return rc;
247}
248
249NTSTATUS vboxWddmGhDisplayPostResizeLegacy(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData, const POINT * pVScreenPos, uint16_t fFlags)
250{
251 int rc;
252
253 if (!(fFlags & (VBVA_SCREEN_F_DISABLED | VBVA_SCREEN_F_BLANK2)))
254 {
255 rc = vboxWddmGhDisplayPostInfoView(pDevExt, pAllocData);
256 if (RT_FAILURE(rc))
257 {
258 WARN(("vboxWddmGhDisplayPostInfoView failed %d", rc));
259 return STATUS_UNSUCCESSFUL;
260 }
261 }
262
263 rc = vboxWddmGhDisplayPostInfoScreen(pDevExt, pAllocData, pVScreenPos, fFlags);
264 if (RT_FAILURE(rc))
265 {
266 WARN(("vboxWddmGhDisplayPostInfoScreen failed %d", rc));
267 return STATUS_UNSUCCESSFUL;
268 }
269
270 return STATUS_SUCCESS;
271}
272
273NTSTATUS vboxWddmGhDisplayPostResizeNew(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData, const uint32_t *pTargetMap, const POINT * pVScreenPos, uint16_t fFlags)
274{
275 RT_NOREF(pDevExt, pAllocData, pTargetMap, pVScreenPos, fFlags);
276 AssertFailed(); // Should not be here.
277 return STATUS_UNSUCCESSFUL;
278}
279
280NTSTATUS vboxWddmGhDisplaySetMode(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData)
281{
282 RT_NOREF(pDevExt);
283 VBOXVIDEOOFFSET offVram = vboxWddmAddrFramOffset(&pAllocData->Addr);;
284 if (offVram == VBOXVIDEOOFFSET_VOID)
285 {
286 WARN(("offVram == VBOXVIDEOOFFSET_VOID"));
287 return STATUS_UNSUCCESSFUL;
288 }
289
290 USHORT width = pAllocData->SurfDesc.width;
291 USHORT height = pAllocData->SurfDesc.height;
292 USHORT bpp = pAllocData->SurfDesc.bpp;
293 ULONG cbLine = VBOXWDDM_ROUNDBOUND(((width * bpp) + 7) / 8, 4);
294 ULONG yOffset = (ULONG)offVram / cbLine;
295 ULONG xOffset = (ULONG)offVram % cbLine;
296
297 if (bpp == 4)
298 {
299 xOffset <<= 1;
300 }
301 else
302 {
303 Assert(!(xOffset%((bpp + 7) >> 3)));
304 xOffset /= ((bpp + 7) >> 3);
305 }
306 Assert(xOffset <= 0xffff);
307 Assert(yOffset <= 0xffff);
308
309 VBoxVideoSetModeRegisters(width, height, width, bpp, 0, (uint16_t)xOffset, (uint16_t)yOffset);
310 /** @todo read back from port to check if mode switch was successful */
311
312 return STATUS_SUCCESS;
313}
314
315static uint16_t vboxWddmCalcScreenFlags(PVBOXMP_DEVEXT pDevExt, bool fValidAlloc, bool fPowerOff, bool fDisabled)
316{
317 uint16_t u16Flags;
318
319 if (fValidAlloc)
320 {
321 u16Flags = VBVA_SCREEN_F_ACTIVE;
322 }
323 else
324 {
325 if ( !fDisabled
326 && fPowerOff
327 && RT_BOOL(VBoxCommonFromDeviceExt(pDevExt)->u16SupportedScreenFlags & VBVA_SCREEN_F_BLANK2))
328 {
329 u16Flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_BLANK2;
330 }
331 else
332 {
333 u16Flags = VBVA_SCREEN_F_DISABLED;
334 }
335 }
336
337 return u16Flags;
338}
339
340NTSTATUS vboxWddmGhDisplaySetInfoLegacy(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData, const POINT * pVScreenPos, uint8_t u8CurCyncState, bool fPowerOff, bool fDisabled)
341{
342 RT_NOREF(u8CurCyncState);
343 NTSTATUS Status = STATUS_SUCCESS;
344 bool fValidAlloc = pAllocData->SurfDesc.width > 0 && pAllocData->SurfDesc.height > 0;
345 uint16_t fu16Flags = vboxWddmCalcScreenFlags(pDevExt, fValidAlloc, fPowerOff, fDisabled);
346
347 if (fValidAlloc)
348 {
349 if (pAllocData->SurfDesc.VidPnSourceId == 0)
350 Status = vboxWddmGhDisplaySetMode(pDevExt, pAllocData);
351 }
352
353 if (NT_SUCCESS(Status))
354 {
355 Status = vboxWddmGhDisplayPostResizeLegacy(pDevExt, pAllocData, pVScreenPos,
356 fu16Flags);
357 if (NT_SUCCESS(Status))
358 {
359 return STATUS_SUCCESS;
360 }
361 else
362 WARN(("vboxWddmGhDisplayPostResize failed, Status 0x%x", Status));
363 }
364 else
365 WARN(("vboxWddmGhDisplaySetMode failed, Status 0x%x", Status));
366
367 return Status;
368}
369
370NTSTATUS vboxWddmGhDisplaySetInfoNew(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData, const uint32_t *pTargetMap, const POINT * pVScreenPos, uint8_t u8CurCyncState, bool fPowerOff, bool fDisabled)
371{
372 RT_NOREF(u8CurCyncState);
373 NTSTATUS Status = STATUS_SUCCESS;
374 bool fValidAlloc = pAllocData->SurfDesc.width > 0 && pAllocData->SurfDesc.height > 0;
375 uint16_t fu16Flags = vboxWddmCalcScreenFlags(pDevExt, fValidAlloc, fPowerOff, fDisabled);
376
377 if (fValidAlloc)
378 {
379 if (ASMBitTest(pTargetMap, 0))
380 Status = vboxWddmGhDisplaySetMode(pDevExt, pAllocData);
381 }
382
383 if (NT_SUCCESS(Status))
384 {
385 Status = vboxWddmGhDisplayPostResizeNew(pDevExt, pAllocData, pTargetMap, pVScreenPos, fu16Flags);
386 if (NT_SUCCESS(Status))
387 {
388 return STATUS_SUCCESS;
389 }
390 else
391 WARN(("vboxWddmGhDisplayPostResizeNew failed, Status 0x%x", Status));
392 }
393 else
394 WARN(("vboxWddmGhDisplaySetMode failed, Status 0x%x", Status));
395
396 return Status;
397}
398
399bool vboxWddmGhDisplayCheckSetInfoFromSourceNew(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource, bool fReportTargets)
400{
401 if (pSource->u8SyncState == VBOXWDDM_HGSYNC_F_SYNCED_ALL)
402 {
403 if (!pSource->fTargetsReported && fReportTargets)
404 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_TOPOLOGY;
405 else
406 return false;
407 }
408
409 if (!pSource->AllocData.Addr.SegmentId && pSource->AllocData.SurfDesc.width)
410 return false;
411
412 VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
413 uint32_t *pTargetMap;
414 if (fReportTargets)
415 pTargetMap = pSource->aTargetMap;
416 else
417 {
418 memset(aTargetMap, 0, sizeof (aTargetMap));
419 pTargetMap = aTargetMap;
420 }
421
422 NTSTATUS Status = vboxWddmGhDisplaySetInfoNew(pDevExt, &pSource->AllocData, pTargetMap, &pSource->VScreenPos, pSource->u8SyncState, RT_BOOL(pSource->bBlankedByPowerOff), false);
423 if (NT_SUCCESS(Status))
424 {
425 if (fReportTargets && (pSource->u8SyncState & VBOXWDDM_HGSYNC_F_CHANGED_LOCATION_ONLY) != VBOXWDDM_HGSYNC_F_CHANGED_LOCATION_ONLY)
426 {
427 VBOXWDDM_TARGET_ITER Iter;
428 VBoxVidPnStTIterInit(pSource, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, &Iter);
429
430 for (PVBOXWDDM_TARGET pTarget = VBoxVidPnStTIterNext(&Iter);
431 pTarget;
432 pTarget = VBoxVidPnStTIterNext(&Iter))
433 {
434 pTarget->u8SyncState = VBOXWDDM_HGSYNC_F_SYNCED_ALL;
435 }
436 }
437
438 pSource->u8SyncState = VBOXWDDM_HGSYNC_F_SYNCED_ALL;
439 pSource->fTargetsReported = !!fReportTargets;
440 return true;
441 }
442
443 WARN(("vboxWddmGhDisplaySetInfoNew failed, Status (0x%x)", Status));
444 return false;
445}
446
447bool vboxWddmGhDisplayCheckSetInfoFromSourceLegacy(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource, bool fReportTargets)
448{
449 if (!fReportTargets)
450 return false;
451
452 if (pSource->u8SyncState == VBOXWDDM_HGSYNC_F_SYNCED_ALL)
453 return false;
454
455 if (!pSource->AllocData.Addr.SegmentId)
456 return false;
457
458 VBOXWDDM_TARGET_ITER Iter;
459 VBoxVidPnStTIterInit(pSource, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, &Iter);
460 uint8_t u8SyncState = VBOXWDDM_HGSYNC_F_SYNCED_ALL;
461 VBOXWDDM_ALLOC_DATA AllocData = pSource->AllocData;
462
463 for (PVBOXWDDM_TARGET pTarget = VBoxVidPnStTIterNext(&Iter);
464 pTarget;
465 pTarget = VBoxVidPnStTIterNext(&Iter))
466 {
467 AllocData.SurfDesc.VidPnSourceId = pTarget->u32Id;
468 NTSTATUS Status = vboxWddmGhDisplaySetInfoLegacy(pDevExt, &AllocData, &pSource->VScreenPos, pSource->u8SyncState | pTarget->u8SyncState, pTarget->fBlankedByPowerOff, pTarget->fDisabled);
469 if (NT_SUCCESS(Status))
470 pTarget->u8SyncState = VBOXWDDM_HGSYNC_F_SYNCED_ALL;
471 else
472 {
473 WARN(("vboxWddmGhDisplaySetInfoLegacy failed, Status (0x%x)", Status));
474 u8SyncState = 0;
475 }
476 }
477
478 pSource->u8SyncState |= u8SyncState;
479
480 return true;
481}
482
483bool vboxWddmGhDisplayCheckSetInfoFromSourceEx(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource, bool fReportTargets)
484{
485 if (pDevExt->fCmdVbvaEnabled)
486 return vboxWddmGhDisplayCheckSetInfoFromSourceNew(pDevExt, pSource, fReportTargets);
487 return vboxWddmGhDisplayCheckSetInfoFromSourceLegacy(pDevExt, pSource, fReportTargets);
488}
489
490bool vboxWddmGhDisplayCheckSetInfoFromSource(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource)
491{
492 bool fReportTargets = !pDevExt->fDisableTargetUpdate;
493 return vboxWddmGhDisplayCheckSetInfoFromSourceEx(pDevExt, pSource, fReportTargets);
494}
495
496bool vboxWddmGhDisplayCheckSetInfoForDisabledTargetsNew(PVBOXMP_DEVEXT pDevExt)
497{
498 VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
499
500 memset(aTargetMap, 0, sizeof (aTargetMap));
501
502 bool fFound = false;
503 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
504 {
505 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
506 Assert(pTarget->u32Id == (unsigned)i);
507 if (pTarget->VidPnSourceId != D3DDDI_ID_UNINITIALIZED)
508 {
509 Assert(pTarget->VidPnSourceId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
510 continue;
511 }
512
513 /* Explicitely disabled targets must not be skipped. */
514 if (pTarget->fBlankedByPowerOff && !pTarget->fDisabled)
515 {
516 LOG(("Skip doing DISABLED request for PowerOff tgt %d", pTarget->u32Id));
517 continue;
518 }
519
520 if (pTarget->u8SyncState != VBOXWDDM_HGSYNC_F_SYNCED_ALL)
521 {
522 ASMBitSet(aTargetMap, i);
523 fFound = true;
524 }
525 }
526
527 if (!fFound)
528 return false;
529
530 POINT VScreenPos = {0};
531 VBOXWDDM_ALLOC_DATA AllocData;
532 VBoxVidPnAllocDataInit(&AllocData, D3DDDI_ID_UNINITIALIZED);
533 NTSTATUS Status = vboxWddmGhDisplaySetInfoNew(pDevExt, &AllocData, aTargetMap, &VScreenPos, 0, false, true);
534 if (!NT_SUCCESS(Status))
535 {
536 WARN(("vboxWddmGhDisplaySetInfoNew failed %#x", Status));
537 return false;
538 }
539
540 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
541 {
542 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
543 if (pTarget->VidPnSourceId != D3DDDI_ID_UNINITIALIZED)
544 {
545 Assert(pTarget->VidPnSourceId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
546 continue;
547 }
548
549 pTarget->u8SyncState = VBOXWDDM_HGSYNC_F_SYNCED_ALL;
550 }
551
552 return true;
553}
554
555bool vboxWddmGhDisplayCheckSetInfoForDisabledTargetsLegacy(PVBOXMP_DEVEXT pDevExt)
556{
557 POINT VScreenPos = {0};
558 bool fFound = false;
559 VBOXWDDM_ALLOC_DATA AllocData;
560 VBoxVidPnAllocDataInit(&AllocData, D3DDDI_ID_UNINITIALIZED);
561
562 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
563 {
564 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
565 Assert(pTarget->u32Id == (unsigned)i);
566 if (pTarget->VidPnSourceId != D3DDDI_ID_UNINITIALIZED)
567 {
568 Assert(pTarget->VidPnSourceId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
569 continue;
570 }
571
572 if (pTarget->u8SyncState == VBOXWDDM_HGSYNC_F_SYNCED_ALL)
573 continue;
574
575 fFound = true;
576 AllocData.SurfDesc.VidPnSourceId = i;
577 NTSTATUS Status = vboxWddmGhDisplaySetInfoLegacy(pDevExt, &AllocData, &VScreenPos, 0, pTarget->fBlankedByPowerOff, pTarget->fDisabled);
578 if (NT_SUCCESS(Status))
579 pTarget->u8SyncState = VBOXWDDM_HGSYNC_F_SYNCED_ALL;
580 else
581 WARN(("vboxWddmGhDisplaySetInfoLegacy failed, Status (0x%x)", Status));
582 }
583
584 return fFound;
585}
586
587void vboxWddmGhDisplayCheckSetInfoForDisabledTargets(PVBOXMP_DEVEXT pDevExt)
588{
589 if (pDevExt->fCmdVbvaEnabled)
590 vboxWddmGhDisplayCheckSetInfoForDisabledTargetsNew(pDevExt);
591 else
592 vboxWddmGhDisplayCheckSetInfoForDisabledTargetsLegacy(pDevExt);
593}
594
595void vboxWddmGhDisplayCheckSetInfoForDisabledTargetsCheck(PVBOXMP_DEVEXT pDevExt)
596{
597 bool fReportTargets = !pDevExt->fDisableTargetUpdate;
598
599 if (fReportTargets)
600 vboxWddmGhDisplayCheckSetInfoForDisabledTargets(pDevExt);
601}
602
603void vboxWddmGhDisplayCheckSetInfoEx(PVBOXMP_DEVEXT pDevExt, bool fReportTargets)
604{
605 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
606 {
607 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[i];
608 vboxWddmGhDisplayCheckSetInfoFromSourceEx(pDevExt, pSource, fReportTargets);
609 }
610
611 if (fReportTargets)
612 vboxWddmGhDisplayCheckSetInfoForDisabledTargets(pDevExt);
613}
614
615void vboxWddmGhDisplayCheckSetInfo(PVBOXMP_DEVEXT pDevExt)
616{
617 bool fReportTargets = !pDevExt->fDisableTargetUpdate;
618 vboxWddmGhDisplayCheckSetInfoEx(pDevExt, fReportTargets);
619}
620
621PVBOXSHGSMI vboxWddmHgsmiGetHeapFromCmdOffset(PVBOXMP_DEVEXT pDevExt, HGSMIOFFSET offCmd)
622{
623 if (HGSMIAreaContainsOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx.Heap.area, offCmd))
624 return &VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx;
625 return NULL;
626}
627
628NTSTATUS vboxWddmPickResources(PVBOXMP_DEVEXT pDevExt, PDXGK_DEVICE_INFO pDeviceInfo, PVBOXWDDM_HWRESOURCES pHwResources)
629{
630 RT_NOREF(pDevExt);
631 NTSTATUS Status = STATUS_SUCCESS;
632 USHORT DispiId;
633 memset(pHwResources, 0, sizeof (*pHwResources));
634 pHwResources->cbVRAM = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
635
636 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
637 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
638 DispiId = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
639 if (DispiId == VBE_DISPI_ID2)
640 {
641 LOGREL(("found the VBE card"));
642 /*
643 * Write some hardware information to registry, so that
644 * it's visible in Windows property dialog.
645 */
646
647 /*
648 * Query the adapter's memory size. It's a bit of a hack, we just read
649 * an ULONG from the data port without setting an index before.
650 */
651 pHwResources->cbVRAM = VBVO_PORT_READ_U32(VBE_DISPI_IOPORT_DATA);
652 if (VBoxHGSMIIsSupported ())
653 {
654 PCM_RESOURCE_LIST pRcList = pDeviceInfo->TranslatedResourceList;
655 /** @todo verify resources */
656 for (ULONG i = 0; i < pRcList->Count; ++i)
657 {
658 PCM_FULL_RESOURCE_DESCRIPTOR pFRc = &pRcList->List[i];
659 for (ULONG j = 0; j < pFRc->PartialResourceList.Count; ++j)
660 {
661 PCM_PARTIAL_RESOURCE_DESCRIPTOR pPRc = &pFRc->PartialResourceList.PartialDescriptors[j];
662 switch (pPRc->Type)
663 {
664 case CmResourceTypePort:
665#ifdef VBOX_WITH_VMSVGA
666 AssertBreak(pHwResources->phIO.QuadPart == 0);
667 pHwResources->phIO = pPRc->u.Port.Start;
668 pHwResources->cbIO = pPRc->u.Port.Length;
669#endif
670 break;
671 case CmResourceTypeInterrupt:
672 break;
673 case CmResourceTypeMemory:
674#ifdef VBOX_WITH_VMSVGA
675 if (pHwResources->phVRAM.QuadPart)
676 {
677 AssertBreak(pHwResources->phFIFO.QuadPart == 0);
678 pHwResources->phFIFO = pPRc->u.Memory.Start;
679 pHwResources->cbFIFO = pPRc->u.Memory.Length;
680 break;
681 }
682#else
683 /* we assume there is one memory segment */
684 AssertBreak(pHwResources->phVRAM.QuadPart == 0);
685#endif
686 pHwResources->phVRAM = pPRc->u.Memory.Start;
687 Assert(pHwResources->phVRAM.QuadPart != 0);
688 pHwResources->ulApertureSize = pPRc->u.Memory.Length;
689 Assert(pHwResources->cbVRAM <= pHwResources->ulApertureSize);
690 break;
691 case CmResourceTypeDma:
692 break;
693 case CmResourceTypeDeviceSpecific:
694 break;
695 case CmResourceTypeBusNumber:
696 break;
697 default:
698 break;
699 }
700 }
701 }
702 }
703 else
704 {
705 LOGREL(("HGSMI unsupported, returning err"));
706 /** @todo report a better status */
707 Status = STATUS_UNSUCCESSFUL;
708 }
709 }
710 else
711 {
712 LOGREL(("VBE card not found, returning err"));
713 Status = STATUS_UNSUCCESSFUL;
714 }
715
716
717 return Status;
718}
719
720static void vboxWddmDevExtZeroinit(PVBOXMP_DEVEXT pDevExt, CONST PDEVICE_OBJECT pPDO)
721{
722 memset(pDevExt, 0, sizeof (VBOXMP_DEVEXT));
723 pDevExt->pPDO = pPDO;
724 PWCHAR pName = (PWCHAR)(((uint8_t*)pDevExt) + VBOXWDDM_ROUNDBOUND(sizeof(VBOXMP_DEVEXT), 8));
725 RtlInitUnicodeString(&pDevExt->RegKeyName, pName);
726
727 VBoxVidPnSourcesInit(pDevExt->aSources, RT_ELEMENTS(pDevExt->aSources), 0);
728
729 VBoxVidPnTargetsInit(pDevExt->aTargets, RT_ELEMENTS(pDevExt->aTargets), 0);
730
731 BOOLEAN f3DSupported = FALSE;
732 uint32_t u32 = 0;
733 if (VBoxVGACfgAvailable())
734 {
735 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_3D, &u32, 0);
736 f3DSupported = RT_BOOL(u32);
737
738 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VMSVGA, &u32, 0);
739 }
740
741 pDevExt->enmHwType = u32 ? VBOXVIDEO_HWTYPE_VMSVGA : VBOXVIDEO_HWTYPE_VBOX;
742
743 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VBOX)
744 {
745 pDevExt->f3DEnabled = FALSE;
746 }
747 else if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
748 {
749 pDevExt->f3DEnabled = f3DSupported;
750 }
751 else
752 {
753 /* No supported 3D hardware, Fallback to VBox 2D only. */
754 pDevExt->enmHwType = VBOXVIDEO_HWTYPE_VBOX;
755 pDevExt->f3DEnabled = FALSE;
756 }
757}
758
759static void vboxWddmSetupDisplaysLegacy(PVBOXMP_DEVEXT pDevExt)
760{
761 /* For WDDM, we simply store the number of monitors as we will deal with
762 * VidPN stuff later */
763 int rc = STATUS_SUCCESS;
764
765 if (VBoxCommonFromDeviceExt(pDevExt)->bHGSMI)
766 {
767 ULONG ulAvailable = VBoxCommonFromDeviceExt(pDevExt)->cbVRAM
768 - VBoxCommonFromDeviceExt(pDevExt)->cbMiniportHeap
769 - VBVA_ADAPTER_INFORMATION_SIZE;
770
771 ULONG ulSize;
772 ULONG offset;
773 offset = ulAvailable;
774 rc = vboxVdmaCreate (pDevExt, &pDevExt->u.primary.Vdma
775 );
776 AssertRC(rc);
777 if (RT_SUCCESS(rc))
778 {
779 /* can enable it right away since the host does not need any screen/FB info
780 * for basic DMA functionality */
781 rc = vboxVdmaEnable(pDevExt, &pDevExt->u.primary.Vdma);
782 AssertRC(rc);
783 if (RT_FAILURE(rc))
784 vboxVdmaDestroy(pDevExt, &pDevExt->u.primary.Vdma);
785 }
786
787 ulAvailable = offset;
788 ulSize = ulAvailable/2;
789 offset = ulAvailable - ulSize;
790
791 NTSTATUS Status = vboxVideoAMgrCreate(pDevExt, &pDevExt->AllocMgr, offset, ulSize);
792 AssertNtStatusSuccess(Status);
793 if (Status != STATUS_SUCCESS)
794 {
795 offset = ulAvailable;
796 }
797
798#ifdef VBOXWDDM_RENDER_FROM_SHADOW
799 if (RT_SUCCESS(rc))
800 {
801 ulAvailable = offset;
802 ulSize = ulAvailable / 2;
803 ulSize /= VBoxCommonFromDeviceExt(pDevExt)->cDisplays;
804 Assert(ulSize > VBVA_MIN_BUFFER_SIZE);
805 if (ulSize > VBVA_MIN_BUFFER_SIZE)
806 {
807 ULONG ulRatio = ulSize/VBVA_MIN_BUFFER_SIZE;
808 ulRatio >>= 4; /* /= 16; */
809 if (ulRatio)
810 ulSize = VBVA_MIN_BUFFER_SIZE * ulRatio;
811 else
812 ulSize = VBVA_MIN_BUFFER_SIZE;
813 }
814 else
815 {
816 /** @todo ?? */
817 }
818
819 ulSize &= ~0xFFF;
820 Assert(ulSize);
821
822 Assert(ulSize * VBoxCommonFromDeviceExt(pDevExt)->cDisplays < ulAvailable);
823
824 for (int i = VBoxCommonFromDeviceExt(pDevExt)->cDisplays-1; i >= 0; --i)
825 {
826 offset -= ulSize;
827 rc = vboxVbvaCreate(pDevExt, &pDevExt->aSources[i].Vbva, offset, ulSize, i);
828 AssertRC(rc);
829 if (RT_SUCCESS(rc))
830 {
831 rc = vboxVbvaEnable(pDevExt, &pDevExt->aSources[i].Vbva);
832 AssertRC(rc);
833 if (RT_FAILURE(rc))
834 {
835 /** @todo de-initialize */
836 }
837 }
838 }
839 }
840#endif
841
842 /* vboxWddmVramCpuVisibleSize uses this value */
843 pDevExt->cbVRAMCpuVisible = offset;
844
845 rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pDevExt->pvVisibleVram,
846 0, vboxWddmVramCpuVisibleSize(pDevExt));
847 Assert(rc == VINF_SUCCESS);
848 if (rc != VINF_SUCCESS)
849 pDevExt->pvVisibleVram = NULL;
850
851 if (RT_FAILURE(rc))
852 VBoxCommonFromDeviceExt(pDevExt)->bHGSMI = FALSE;
853 }
854}
855
856static NTSTATUS vboxWddmSetupDisplaysNew(PVBOXMP_DEVEXT pDevExt)
857{
858 if (!VBoxCommonFromDeviceExt(pDevExt)->bHGSMI)
859 return STATUS_UNSUCCESSFUL;
860
861 ULONG cbAvailable = VBoxCommonFromDeviceExt(pDevExt)->cbVRAM
862 - VBoxCommonFromDeviceExt(pDevExt)->cbMiniportHeap
863 - VBVA_ADAPTER_INFORMATION_SIZE;
864
865 /* vboxWddmVramCpuVisibleSize uses this value */
866 pDevExt->cbVRAMCpuVisible = cbAvailable;
867
868 int rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pDevExt->pvVisibleVram,
869 0, vboxWddmVramCpuVisibleSize(pDevExt));
870 if (RT_FAILURE(rc))
871 {
872 WARN(("VBoxMPCmnMapAdapterMemory failed, rc %d", rc));
873 return STATUS_UNSUCCESSFUL;
874 }
875
876 return STATUS_SUCCESS;
877}
878
879static NTSTATUS vboxWddmSetupDisplays(PVBOXMP_DEVEXT pDevExt)
880{
881 if (pDevExt->fCmdVbvaEnabled)
882 {
883 NTSTATUS Status = vboxWddmSetupDisplaysNew(pDevExt);
884 if (!NT_SUCCESS(Status))
885 VBoxCommonFromDeviceExt(pDevExt)->bHGSMI = FALSE;
886 return Status;
887 }
888
889 vboxWddmSetupDisplaysLegacy(pDevExt);
890 return VBoxCommonFromDeviceExt(pDevExt)->bHGSMI ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
891}
892
893static int vboxWddmFreeDisplays(PVBOXMP_DEVEXT pDevExt)
894{
895 int rc = VINF_SUCCESS;
896
897 Assert(pDevExt->pvVisibleVram);
898 if (pDevExt->pvVisibleVram)
899 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pDevExt->pvVisibleVram);
900
901 if (!pDevExt->fCmdVbvaEnabled)
902 {
903 for (int i = VBoxCommonFromDeviceExt(pDevExt)->cDisplays-1; i >= 0; --i)
904 {
905 rc = vboxVbvaDisable(pDevExt, &pDevExt->aSources[i].Vbva);
906 AssertRC(rc);
907 if (RT_SUCCESS(rc))
908 {
909 rc = vboxVbvaDestroy(pDevExt, &pDevExt->aSources[i].Vbva);
910 AssertRC(rc);
911 if (RT_FAILURE(rc))
912 {
913 /** @todo */
914 }
915 }
916 }
917
918 vboxVideoAMgrDestroy(pDevExt, &pDevExt->AllocMgr);
919
920 rc = vboxVdmaDisable(pDevExt, &pDevExt->u.primary.Vdma);
921 AssertRC(rc);
922 if (RT_SUCCESS(rc))
923 {
924 rc = vboxVdmaDestroy(pDevExt, &pDevExt->u.primary.Vdma);
925 AssertRC(rc);
926 }
927 }
928
929 return rc;
930}
931
932
933/* driver callbacks */
934NTSTATUS DxgkDdiAddDevice(
935 IN CONST PDEVICE_OBJECT PhysicalDeviceObject,
936 OUT PVOID *MiniportDeviceContext
937 )
938{
939 /* The DxgkDdiAddDevice function should be made pageable. */
940 PAGED_CODE();
941
942 LOGF(("ENTER, pdo(0x%x)", PhysicalDeviceObject));
943
944 vboxVDbgBreakFv();
945
946 NTSTATUS Status = STATUS_SUCCESS;
947 PVBOXMP_DEVEXT pDevExt = NULL;
948
949 WCHAR RegKeyBuf[512];
950 ULONG cbRegKeyBuf = sizeof (RegKeyBuf);
951
952 Status = IoGetDeviceProperty (PhysicalDeviceObject,
953 DevicePropertyDriverKeyName,
954 cbRegKeyBuf,
955 RegKeyBuf,
956 &cbRegKeyBuf);
957 AssertNtStatusSuccess(Status);
958 if (Status == STATUS_SUCCESS)
959 {
960 pDevExt = (PVBOXMP_DEVEXT)vboxWddmMemAllocZero(VBOXWDDM_ROUNDBOUND(sizeof(VBOXMP_DEVEXT), 8) + cbRegKeyBuf);
961 if (pDevExt)
962 {
963 PWCHAR pName = (PWCHAR)(((uint8_t*)pDevExt) + VBOXWDDM_ROUNDBOUND(sizeof(VBOXMP_DEVEXT), 8));
964 memcpy(pName, RegKeyBuf, cbRegKeyBuf);
965 vboxWddmDevExtZeroinit(pDevExt, PhysicalDeviceObject);
966 *MiniportDeviceContext = pDevExt;
967 }
968 else
969 {
970 Status = STATUS_NO_MEMORY;
971 LOGREL(("ERROR, failed to create context"));
972 }
973 }
974
975 LOGF(("LEAVE, Status(0x%x), pDevExt(0x%x)", Status, pDevExt));
976
977 return Status;
978}
979
980NTSTATUS DxgkDdiStartDevice(
981 IN CONST PVOID MiniportDeviceContext,
982 IN PDXGK_START_INFO DxgkStartInfo,
983 IN PDXGKRNL_INTERFACE DxgkInterface,
984 OUT PULONG NumberOfVideoPresentSources,
985 OUT PULONG NumberOfChildren
986 )
987{
988 /* The DxgkDdiStartDevice function should be made pageable. */
989 PAGED_CODE();
990
991 NTSTATUS Status;
992
993 LOGF(("ENTER, context(0x%x)", MiniportDeviceContext));
994
995 vboxVDbgBreakFv();
996
997 if ( ARGUMENT_PRESENT(MiniportDeviceContext) &&
998 ARGUMENT_PRESENT(DxgkInterface) &&
999 ARGUMENT_PRESENT(DxgkStartInfo) &&
1000 ARGUMENT_PRESENT(NumberOfVideoPresentSources) &&
1001 ARGUMENT_PRESENT(NumberOfChildren)
1002 )
1003 {
1004 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
1005
1006 vboxWddmVGuidGet(pDevExt);
1007
1008 /* Save DeviceHandle and function pointers supplied by the DXGKRNL_INTERFACE structure passed to DxgkInterface. */
1009 memcpy(&pDevExt->u.primary.DxgkInterface, DxgkInterface, sizeof (DXGKRNL_INTERFACE));
1010
1011 /* Allocate a DXGK_DEVICE_INFO structure, and call DxgkCbGetDeviceInformation to fill in the members of that structure, which include the registry path, the PDO, and a list of translated resources for the display adapter represented by MiniportDeviceContext. Save selected members (ones that the display miniport driver will need later)
1012 * of the DXGK_DEVICE_INFO structure in the context block represented by MiniportDeviceContext. */
1013 DXGK_DEVICE_INFO DeviceInfo;
1014 Status = pDevExt->u.primary.DxgkInterface.DxgkCbGetDeviceInformation (pDevExt->u.primary.DxgkInterface.DeviceHandle, &DeviceInfo);
1015 if (Status == STATUS_SUCCESS)
1016 {
1017 Status = vboxWddmPickResources(pDevExt, &DeviceInfo, &pDevExt->HwResources);
1018 if (Status == STATUS_SUCCESS)
1019 {
1020 /* Figure out the host capabilities. Start with nothing. */
1021 pDevExt->fCmdVbvaEnabled = FALSE;
1022 pDevExt->fComplexTopologiesEnabled = TRUE;
1023
1024 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VBOX)
1025 {
1026 pDevExt->f3DEnabled = FALSE;
1027 }
1028#ifdef VBOX_WITH_VMSVGA
1029 else if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
1030 {
1031 if (pDevExt->f3DEnabled)
1032 {
1033 /// @todo This enables legacy code which is shared with VMSVGA, for example displays setup.
1034 // Must be removed eventually.
1035 pDevExt->fCmdVbvaEnabled = TRUE;
1036 pDevExt->fComplexTopologiesEnabled = TRUE; /** @todo Implement clones support. */
1037 }
1038 }
1039#endif /* VBOX_WITH_VMSVGA */
1040 else
1041 {
1042 pDevExt->f3DEnabled = FALSE;
1043 }
1044
1045 LOGREL(("Handling complex topologies %s", pDevExt->fComplexTopologiesEnabled ? "enabled" : "disabled"));
1046
1047 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported.
1048 * The host will however support both old and new interface to keep compatibility
1049 * with old guest additions.
1050 */
1051 VBoxSetupDisplaysHGSMI(VBoxCommonFromDeviceExt(pDevExt),
1052 pDevExt->HwResources.phVRAM, pDevExt->HwResources.ulApertureSize, pDevExt->HwResources.cbVRAM,
1053 VBVACAPS_COMPLETEGCMD_BY_IOREAD | VBVACAPS_IRQ);
1054 if (VBoxCommonFromDeviceExt(pDevExt)->bHGSMI)
1055 {
1056 vboxWddmSetupDisplays(pDevExt);
1057 if (!VBoxCommonFromDeviceExt(pDevExt)->bHGSMI)
1058 VBoxFreeDisplaysHGSMI(VBoxCommonFromDeviceExt(pDevExt));
1059 }
1060 if (VBoxCommonFromDeviceExt(pDevExt)->bHGSMI)
1061 {
1062 LOGREL(("using HGSMI"));
1063 *NumberOfVideoPresentSources = VBoxCommonFromDeviceExt(pDevExt)->cDisplays;
1064 *NumberOfChildren = VBoxCommonFromDeviceExt(pDevExt)->cDisplays;
1065 LOG(("sources(%d), children(%d)", *NumberOfVideoPresentSources, *NumberOfChildren));
1066
1067 vboxVdmaDdiNodesInit(pDevExt);
1068 vboxVideoCmInit(&pDevExt->CmMgr);
1069 vboxVideoCmInit(&pDevExt->SeamlessCtxMgr);
1070 pDevExt->cContexts3D = 0;
1071 pDevExt->cContexts2D = 0;
1072 pDevExt->cContextsDispIfResize = 0;
1073 pDevExt->cUnlockedVBVADisabled = 0;
1074 pDevExt->fDisableTargetUpdate = 0;
1075 VBOXWDDM_CTXLOCK_INIT(pDevExt);
1076 KeInitializeSpinLock(&pDevExt->SynchLock);
1077
1078 VBoxCommonFromDeviceExt(pDevExt)->fAnyX = VBoxVideoAnyWidthAllowed();
1079#if 0
1080 vboxShRcTreeInit(pDevExt);
1081#endif
1082
1083#ifdef VBOX_WITH_VIDEOHWACCEL
1084 vboxVhwaInit(pDevExt);
1085#endif
1086 VBoxWddmSlInit(pDevExt);
1087
1088 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1089 {
1090 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[i];
1091 KeInitializeSpinLock(&pSource->AllocationLock);
1092 }
1093
1094 DWORD dwVal = VBOXWDDM_CFG_DRV_DEFAULT;
1095 HANDLE hKey = NULL;
1096
1097 Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_READ, &hKey);
1098 if (!NT_SUCCESS(Status))
1099 {
1100 WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
1101 hKey = NULL;
1102 }
1103
1104
1105 if (hKey)
1106 {
1107 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, &dwVal);
1108 if (!NT_SUCCESS(Status))
1109 {
1110 LOG(("vboxWddmRegQueryValueDword failed, Status = 0x%x", Status));
1111 dwVal = VBOXWDDM_CFG_DRV_DEFAULT;
1112 }
1113 }
1114
1115 pDevExt->dwDrvCfgFlags = dwVal;
1116
1117 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1118 {
1119 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i];
1120 if (i == 0 || (pDevExt->dwDrvCfgFlags & VBOXWDDM_CFG_DRV_SECONDARY_TARGETS_CONNECTED) || !hKey)
1121 {
1122 pTarget->fConnected = true;
1123 pTarget->fConfigured = true;
1124 }
1125 else if (hKey)
1126 {
1127 WCHAR wszNameBuf[sizeof(VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX) / sizeof(WCHAR) + 32];
1128 RTUtf16Printf(wszNameBuf, RT_ELEMENTS(wszNameBuf), "%ls%u", VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX, i);
1129 Status = vboxWddmRegQueryValueDword(hKey, wszNameBuf, &dwVal);
1130 if (NT_SUCCESS(Status))
1131 {
1132 pTarget->fConnected = !!(dwVal & VBOXWDDM_CFG_DRVTARGET_CONNECTED);
1133 pTarget->fConfigured = true;
1134 }
1135 else
1136 {
1137 WARN(("vboxWddmRegQueryValueDword failed, Status = 0x%x", Status));
1138 pTarget->fConnected = false;
1139 pTarget->fConfigured = false;
1140 }
1141 }
1142 }
1143
1144 if (hKey)
1145 {
1146 NTSTATUS rcNt2 = ZwClose(hKey);
1147 Assert(rcNt2 == STATUS_SUCCESS); NOREF(rcNt2);
1148 }
1149
1150 Status = STATUS_SUCCESS;
1151
1152 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
1153 {
1154 DXGK_DISPLAY_INFORMATION DisplayInfo;
1155 Status = pDevExt->u.primary.DxgkInterface.DxgkCbAcquirePostDisplayOwnership(pDevExt->u.primary.DxgkInterface.DeviceHandle,
1156 &DisplayInfo);
1157 if (NT_SUCCESS(Status))
1158 {
1159 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[0];
1160 PHYSICAL_ADDRESS PhAddr;
1161 /* display info may sometimes not be valid, e.g. on from-full-graphics wddm driver update
1162 * ensure we have something meaningful here */
1163 if (!DisplayInfo.Width)
1164 {
1165 PhAddr = VBoxCommonFromDeviceExt(pDevExt)->phVRAM;
1166 vboxWddmDiInitDefault(&DisplayInfo, PhAddr, 0);
1167 }
1168 else
1169 {
1170 PhAddr = DisplayInfo.PhysicAddress;
1171 DisplayInfo.TargetId = 0;
1172 }
1173
1174 vboxWddmDiToAllocData(pDevExt, &DisplayInfo, &pSource->AllocData);
1175
1176 /* init the rest source infos with some default values */
1177 for (UINT i = 1; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1178 {
1179 PhAddr.QuadPart += pSource->AllocData.SurfDesc.cbSize;
1180 PhAddr.QuadPart = ROUND_TO_PAGES(PhAddr.QuadPart);
1181 vboxWddmDiInitDefault(&DisplayInfo, PhAddr, i);
1182 pSource = &pDevExt->aSources[i];
1183 vboxWddmDiToAllocData(pDevExt, &DisplayInfo, &pSource->AllocData);
1184 }
1185 }
1186 else
1187 {
1188 WARN(("DxgkCbAcquirePostDisplayOwnership failed, Status 0x%x", Status));
1189 }
1190 }
1191
1192 VBoxWddmVModesInit(pDevExt);
1193
1194#ifdef VBOX_WITH_VMSVGA
1195 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
1196 {
1197 LOGREL(("WDDM: VRAM %#RX64/%#RX32, FIFO %#RX64/%#RX32, IO %#RX64/%#RX32",
1198 pDevExt->HwResources.phVRAM.QuadPart, pDevExt->HwResources.cbVRAM,
1199 pDevExt->HwResources.phFIFO.QuadPart, pDevExt->HwResources.cbFIFO,
1200 pDevExt->HwResources.phIO.QuadPart, pDevExt->HwResources.cbIO));
1201
1202 Status = GaAdapterStart(pDevExt);
1203 if (Status == STATUS_SUCCESS)
1204 { /* likely */ }
1205 else
1206 LOGREL(("WDDM: GaAdapterStart failed Status(0x%x)", Status));
1207 }
1208#endif
1209 }
1210 else
1211 {
1212 LOGREL(("HGSMI failed to initialize, returning err"));
1213
1214 /** @todo report a better status */
1215 Status = STATUS_UNSUCCESSFUL;
1216 }
1217 }
1218 else
1219 {
1220 LOGREL(("vboxWddmPickResources failed Status(0x%x), returning err", Status));
1221 Status = STATUS_UNSUCCESSFUL;
1222 }
1223 }
1224 else
1225 {
1226 LOGREL(("DxgkCbGetDeviceInformation failed Status(0x%x), returning err", Status));
1227 }
1228 }
1229 else
1230 {
1231 LOGREL(("invalid parameter, returning err"));
1232 Status = STATUS_INVALID_PARAMETER;
1233 }
1234
1235 LOGF(("LEAVE, status(0x%x)", Status));
1236
1237 return Status;
1238}
1239
1240NTSTATUS DxgkDdiStopDevice(
1241 IN CONST PVOID MiniportDeviceContext
1242 )
1243{
1244 /* The DxgkDdiStopDevice function should be made pageable. */
1245 PAGED_CODE();
1246
1247 LOGF(("ENTER, context(0x%p)", MiniportDeviceContext));
1248
1249 vboxVDbgBreakFv();
1250
1251 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
1252 NTSTATUS Status = STATUS_SUCCESS;
1253
1254#ifdef VBOX_WITH_VMSVGA
1255 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
1256 {
1257 GaAdapterStop(pDevExt);
1258 }
1259#endif
1260
1261 VBoxWddmSlTerm(pDevExt);
1262
1263 vboxVideoCmTerm(&pDevExt->CmMgr);
1264
1265 vboxVideoCmTerm(&pDevExt->SeamlessCtxMgr);
1266
1267 /* do everything we did on DxgkDdiStartDevice in the reverse order */
1268#ifdef VBOX_WITH_VIDEOHWACCEL
1269 vboxVhwaFree(pDevExt);
1270#endif
1271#if 0
1272 vboxShRcTreeTerm(pDevExt);
1273#endif
1274
1275 int rc = vboxWddmFreeDisplays(pDevExt);
1276 if (RT_SUCCESS(rc))
1277 VBoxFreeDisplaysHGSMI(VBoxCommonFromDeviceExt(pDevExt));
1278 AssertRC(rc);
1279 if (RT_SUCCESS(rc))
1280 {
1281 vboxWddmVGuidFree(pDevExt);
1282
1283 VBoxWddmVModesCleanup();
1284 /* revert back to the state we were right after the DxgkDdiAddDevice */
1285 vboxWddmDevExtZeroinit(pDevExt, pDevExt->pPDO);
1286 }
1287 else
1288 Status = STATUS_UNSUCCESSFUL;
1289
1290 return Status;
1291}
1292
1293NTSTATUS DxgkDdiRemoveDevice(
1294 IN CONST PVOID MiniportDeviceContext
1295 )
1296{
1297 /* DxgkDdiRemoveDevice should be made pageable. */
1298 PAGED_CODE();
1299
1300 LOGF(("ENTER, context(0x%p)", MiniportDeviceContext));
1301
1302 vboxVDbgBreakFv();
1303
1304 vboxWddmMemFree(MiniportDeviceContext);
1305
1306 LOGF(("LEAVE, context(0x%p)", MiniportDeviceContext));
1307
1308 return STATUS_SUCCESS;
1309}
1310
1311NTSTATUS DxgkDdiDispatchIoRequest(
1312 IN CONST PVOID MiniportDeviceContext,
1313 IN ULONG VidPnSourceId,
1314 IN PVIDEO_REQUEST_PACKET VideoRequestPacket
1315 )
1316{
1317 LOGF(("ENTER, context(0x%p), ctl(0x%x)", MiniportDeviceContext, VideoRequestPacket->IoControlCode));
1318
1319 AssertBreakpoint();
1320#if 0
1321 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
1322
1323 switch (VideoRequestPacket->IoControlCode)
1324 {
1325 case IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES:
1326 {
1327 if (VideoRequestPacket->OutputBufferLength < sizeof(VIDEO_COLOR_CAPABILITIES))
1328 {
1329 AssertBreakpoint();
1330 VideoRequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1331 return TRUE;
1332 }
1333 VIDEO_COLOR_CAPABILITIES *pCaps = (VIDEO_COLOR_CAPABILITIES*)VideoRequestPacket->OutputBuffer;
1334
1335 pCaps->Length = sizeof (VIDEO_COLOR_CAPABILITIES);
1336 pCaps->AttributeFlags = VIDEO_DEVICE_COLOR;
1337 pCaps->RedPhosphoreDecay = 0;
1338 pCaps->GreenPhosphoreDecay = 0;
1339 pCaps->BluePhosphoreDecay = 0;
1340 pCaps->WhiteChromaticity_x = 3127;
1341 pCaps->WhiteChromaticity_y = 3290;
1342 pCaps->WhiteChromaticity_Y = 0;
1343 pCaps->RedChromaticity_x = 6700;
1344 pCaps->RedChromaticity_y = 3300;
1345 pCaps->GreenChromaticity_x = 2100;
1346 pCaps->GreenChromaticity_y = 7100;
1347 pCaps->BlueChromaticity_x = 1400;
1348 pCaps->BlueChromaticity_y = 800;
1349 pCaps->WhiteGamma = 0;
1350 pCaps->RedGamma = 20000;
1351 pCaps->GreenGamma = 20000;
1352 pCaps->BlueGamma = 20000;
1353
1354 VideoRequestPacket->StatusBlock->Status = NO_ERROR;
1355 VideoRequestPacket->StatusBlock->Information = sizeof (VIDEO_COLOR_CAPABILITIES);
1356 break;
1357 }
1358#if 0
1359 case IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS:
1360 {
1361 if (VideoRequestPacket->OutputBufferLength < sizeof(VIDEOPARAMETERS)
1362 || VideoRequestPacket->InputBufferLength < sizeof(VIDEOPARAMETERS))
1363 {
1364 AssertBreakpoint();
1365 VideoRequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1366 return TRUE;
1367 }
1368
1369 Result = VBoxVideoResetDevice((PVBOXMP_DEVEXT)HwDeviceExtension,
1370 RequestPacket->StatusBlock);
1371 break;
1372 }
1373#endif
1374 default:
1375 AssertBreakpoint();
1376 VideoRequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1377 VideoRequestPacket->StatusBlock->Information = 0;
1378 }
1379#else
1380 RT_NOREF(MiniportDeviceContext, VidPnSourceId, VideoRequestPacket);
1381#endif
1382 LOGF(("LEAVE, context(0x%p), ctl(0x%x)", MiniportDeviceContext, VideoRequestPacket->IoControlCode));
1383
1384 return STATUS_SUCCESS;
1385}
1386
1387NTSTATUS DxgkDdiQueryChildRelations(
1388 IN CONST PVOID MiniportDeviceContext,
1389 IN OUT PDXGK_CHILD_DESCRIPTOR ChildRelations,
1390 IN ULONG ChildRelationsSize
1391 )
1392{
1393 RT_NOREF(ChildRelationsSize);
1394 /* The DxgkDdiQueryChildRelations function should be made pageable. */
1395 PAGED_CODE();
1396
1397 vboxVDbgBreakFv();
1398
1399 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
1400
1401 LOGF(("ENTER, context(0x%x)", MiniportDeviceContext));
1402 Assert(ChildRelationsSize == (VBoxCommonFromDeviceExt(pDevExt)->cDisplays + 1)*sizeof(DXGK_CHILD_DESCRIPTOR));
1403 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1404 {
1405 ChildRelations[i].ChildDeviceType = TypeVideoOutput;
1406 ChildRelations[i].ChildCapabilities.Type.VideoOutput.InterfaceTechnology = D3DKMDT_VOT_HD15; /* VGA */
1407 ChildRelations[i].ChildCapabilities.Type.VideoOutput.MonitorOrientationAwareness = D3DKMDT_MOA_NONE; //D3DKMDT_MOA_INTERRUPTIBLE; /* ?? D3DKMDT_MOA_NONE*/
1408 ChildRelations[i].ChildCapabilities.Type.VideoOutput.SupportsSdtvModes = FALSE;
1409 ChildRelations[i].ChildCapabilities.HpdAwareness = HpdAwarenessInterruptible; /* ?? HpdAwarenessAlwaysConnected; */
1410 ChildRelations[i].AcpiUid = 0; /* */
1411 ChildRelations[i].ChildUid = i; /* should be == target id */
1412 }
1413 LOGF(("LEAVE, context(0x%x)", MiniportDeviceContext));
1414 return STATUS_SUCCESS;
1415}
1416
1417NTSTATUS DxgkDdiQueryChildStatus(
1418 IN CONST PVOID MiniportDeviceContext,
1419 IN PDXGK_CHILD_STATUS ChildStatus,
1420 IN BOOLEAN NonDestructiveOnly
1421 )
1422{
1423 RT_NOREF(NonDestructiveOnly);
1424 /* The DxgkDdiQueryChildStatus should be made pageable. */
1425 PAGED_CODE();
1426
1427 vboxVDbgBreakFv();
1428
1429 LOGF(("ENTER, context(0x%x)", MiniportDeviceContext));
1430
1431 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
1432
1433 if (ChildStatus->ChildUid >= (uint32_t)VBoxCommonFromDeviceExt(pDevExt)->cDisplays)
1434 {
1435 WARN(("Invalid child id %d", ChildStatus->ChildUid));
1436 return STATUS_INVALID_PARAMETER;
1437 }
1438
1439 NTSTATUS Status = STATUS_SUCCESS;
1440 switch (ChildStatus->Type)
1441 {
1442 case StatusConnection:
1443 {
1444 LOGF(("StatusConnection"));
1445 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[ChildStatus->ChildUid];
1446 BOOLEAN Connected = !!pTarget->fConnected;
1447 if (!Connected)
1448 LOGREL(("Tgt[%d] DISCONNECTED!!", ChildStatus->ChildUid));
1449 ChildStatus->HotPlug.Connected = !!pTarget->fConnected;
1450 break;
1451 }
1452 case StatusRotation:
1453 LOGF(("StatusRotation"));
1454 ChildStatus->Rotation.Angle = 0;
1455 break;
1456 default:
1457 WARN(("ERROR: status type: %d", ChildStatus->Type));
1458 Status = STATUS_INVALID_PARAMETER;
1459 break;
1460 }
1461
1462 LOGF(("LEAVE, context(0x%x)", MiniportDeviceContext));
1463
1464 return Status;
1465}
1466
1467NTSTATUS DxgkDdiQueryDeviceDescriptor(
1468 IN CONST PVOID MiniportDeviceContext,
1469 IN ULONG ChildUid,
1470 IN OUT PDXGK_DEVICE_DESCRIPTOR DeviceDescriptor
1471 )
1472{
1473 RT_NOREF(MiniportDeviceContext, ChildUid, DeviceDescriptor);
1474 /* The DxgkDdiQueryDeviceDescriptor should be made pageable. */
1475 PAGED_CODE();
1476
1477 vboxVDbgBreakFv();
1478
1479 LOGF(("ENTER, context(0x%x)", MiniportDeviceContext));
1480
1481 LOGF(("LEAVE, context(0x%x)", MiniportDeviceContext));
1482
1483 /* we do not support EDID */
1484 return STATUS_MONITOR_NO_DESCRIPTOR;
1485}
1486
1487NTSTATUS DxgkDdiSetPowerState(
1488 IN CONST PVOID MiniportDeviceContext,
1489 IN ULONG DeviceUid,
1490 IN DEVICE_POWER_STATE DevicePowerState,
1491 IN POWER_ACTION ActionType
1492 )
1493{
1494 RT_NOREF(MiniportDeviceContext, DeviceUid, DevicePowerState, ActionType);
1495 /* The DxgkDdiSetPowerState function should be made pageable. */
1496 PAGED_CODE();
1497
1498 LOGF(("ENTER, context(0x%x)", MiniportDeviceContext));
1499
1500 vboxVDbgBreakFv();
1501
1502 LOGF(("LEAVE, context(0x%x)", MiniportDeviceContext));
1503
1504 return STATUS_SUCCESS;
1505}
1506
1507NTSTATUS DxgkDdiNotifyAcpiEvent(
1508 IN CONST PVOID MiniportDeviceContext,
1509 IN DXGK_EVENT_TYPE EventType,
1510 IN ULONG Event,
1511 IN PVOID Argument,
1512 OUT PULONG AcpiFlags
1513 )
1514{
1515 RT_NOREF(MiniportDeviceContext, EventType, Event, Argument, AcpiFlags);
1516 LOGF(("ENTER, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
1517
1518 vboxVDbgBreakF();
1519
1520 LOGF(("LEAVE, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
1521
1522 return STATUS_SUCCESS;
1523}
1524
1525VOID DxgkDdiResetDevice(
1526 IN CONST PVOID MiniportDeviceContext
1527 )
1528{
1529 RT_NOREF(MiniportDeviceContext);
1530 /* DxgkDdiResetDevice can be called at any IRQL, so it must be in nonpageable memory. */
1531 vboxVDbgBreakF();
1532
1533
1534
1535 LOGF(("ENTER, context(0x%x)", MiniportDeviceContext));
1536 LOGF(("LEAVE, context(0x%x)", MiniportDeviceContext));
1537}
1538
1539VOID DxgkDdiUnload(
1540 VOID
1541 )
1542{
1543 /* DxgkDdiUnload should be made pageable. */
1544 PAGED_CODE();
1545 LOGF((": unloading"));
1546
1547 vboxVDbgBreakFv();
1548
1549 VbglR0TerminateClient();
1550
1551 PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
1552 if (pLogger)
1553 {
1554 RTLogDestroy(pLogger);
1555 }
1556 pLogger = RTLogSetDefaultInstance(NULL);
1557 if (pLogger)
1558 {
1559 RTLogDestroy(pLogger);
1560 }
1561
1562 RTR0Term();
1563}
1564
1565NTSTATUS DxgkDdiQueryInterface(
1566 IN CONST PVOID MiniportDeviceContext,
1567 IN PQUERY_INTERFACE QueryInterface
1568 )
1569{
1570 RT_NOREF(MiniportDeviceContext, QueryInterface);
1571 LOGF(("ENTER, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
1572
1573 vboxVDbgBreakFv();
1574
1575 LOGF(("LEAVE, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
1576
1577 return STATUS_NOT_SUPPORTED;
1578}
1579
1580VOID DxgkDdiControlEtwLogging(
1581 IN BOOLEAN Enable,
1582 IN ULONG Flags,
1583 IN UCHAR Level
1584 )
1585{
1586 RT_NOREF(Enable, Flags, Level);
1587 LOGF(("ENTER"));
1588
1589 vboxVDbgBreakF();
1590
1591 LOGF(("LEAVE"));
1592}
1593
1594#ifdef VBOX_WITH_VMSVGA3D_DX
1595typedef struct VBOXDXSEGMENTDESCRIPTOR
1596{
1597 DXGK_SEGMENTFLAGS Flags;
1598 PHYSICAL_ADDRESS CpuTranslatedAddress;
1599 SIZE_T Size;
1600} VBOXDXSEGMENTDESCRIPTOR;
1601
1602#define VBOXDX_SEGMENTS_COUNT 3
1603
1604static void vmsvgaDXGetSegmentDescription(PVBOXMP_DEVEXT pDevExt, int idxSegment, VBOXDXSEGMENTDESCRIPTOR *pDesc)
1605{
1606 /** @todo 2 segments for pDevExt->fLegacy flag. */
1607 /* 3 segments:
1608 * 1: The usual VRAM, CpuVisible;
1609 * 2: Aperture segment for guest backed objects;
1610 * 3: Host resources, CPU invisible.
1611 */
1612 RT_ZERO(*pDesc);
1613 if (idxSegment == 0)
1614 {
1615 pDesc->CpuTranslatedAddress = VBoxCommonFromDeviceExt(pDevExt)->phVRAM;
1616 pDesc->Size = pDevExt->cbVRAMCpuVisible & X86_PAGE_4K_BASE_MASK;
1617 pDesc->Flags.CpuVisible = 1;
1618 }
1619 else if (idxSegment == 1)
1620 {
1621 pDesc->Size = _2G; /** @todo */
1622 pDesc->Flags.CpuVisible = 1;
1623 pDesc->Flags.Aperture = 1;
1624 }
1625 else if (idxSegment == 2)
1626 {
1627 pDesc->Size = _2G; /** @todo */
1628 }
1629}
1630#endif
1631
1632/**
1633 * DxgkDdiQueryAdapterInfo
1634 */
1635NTSTATUS APIENTRY DxgkDdiQueryAdapterInfo(
1636 CONST HANDLE hAdapter,
1637 CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo)
1638{
1639 /* The DxgkDdiQueryAdapterInfo should be made pageable. */
1640 PAGED_CODE();
1641
1642 LOGF(("ENTER, context(0x%x), Query type (%d)", hAdapter, pQueryAdapterInfo->Type));
1643 NTSTATUS Status = STATUS_SUCCESS;
1644 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
1645
1646 vboxVDbgBreakFv();
1647
1648 switch (pQueryAdapterInfo->Type)
1649 {
1650 case DXGKQAITYPE_DRIVERCAPS:
1651 {
1652 DXGK_DRIVERCAPS *pCaps = (DXGK_DRIVERCAPS*)pQueryAdapterInfo->pOutputData;
1653 memset(pCaps, 0, pQueryAdapterInfo->OutputDataSize);
1654
1655 pCaps->HighestAcceptableAddress.LowPart = ~0UL;
1656#ifdef RT_ARCH_AMD64
1657 /* driver talks to host in terms of page numbers when reffering to RAM
1658 * we use uint32_t field to pass page index to host, so max would be (~0UL) << PAGE_OFFSET,
1659 * which seems quite enough */
1660 pCaps->HighestAcceptableAddress.HighPart = PAGE_OFFSET_MASK;
1661#endif
1662 pCaps->MaxPointerWidth = VBOXWDDM_C_POINTER_MAX_WIDTH;
1663 pCaps->MaxPointerHeight = VBOXWDDM_C_POINTER_MAX_HEIGHT;
1664#ifdef VBOX_WITH_VMSVGA
1665 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VBOX)
1666 {
1667 pCaps->MaxPointerWidth = VBOXWDDM_C_POINTER_MAX_WIDTH_LEGACY;
1668 pCaps->MaxPointerHeight = VBOXWDDM_C_POINTER_MAX_HEIGHT_LEGACY;
1669 }
1670#endif
1671 pCaps->PointerCaps.Value = 3; /* Monochrome , Color*/ /* MaskedColor == Value | 4, disable for now */
1672 if (!g_VBoxDisplayOnly)
1673 {
1674 pCaps->MaxAllocationListSlotId = 16;
1675 pCaps->ApertureSegmentCommitLimit = 0;
1676 pCaps->InterruptMessageNumber = 0;
1677 pCaps->NumberOfSwizzlingRanges = 0;
1678 pCaps->MaxOverlays = 0;
1679#ifdef VBOX_WITH_VIDEOHWACCEL
1680 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1681 {
1682 if ( pDevExt->aSources[i].Vhwa.Settings.fFlags & VBOXVHWA_F_ENABLED)
1683 pCaps->MaxOverlays += pDevExt->aSources[i].Vhwa.Settings.cOverlaysSupported;
1684 }
1685#endif
1686 pCaps->GammaRampCaps.Value = 0;
1687 pCaps->PresentationCaps.Value = 0;
1688 pCaps->PresentationCaps.NoScreenToScreenBlt = 1;
1689 pCaps->PresentationCaps.NoOverlapScreenBlt = 1;
1690 pCaps->PresentationCaps.AlignmentShift = 2;
1691 pCaps->PresentationCaps.MaxTextureWidthShift = 2; /* Up to 8196 */
1692 pCaps->PresentationCaps.MaxTextureHeightShift = 2; /* Up to 8196 */
1693 pCaps->MaxQueuedFlipOnVSync = 0; /* do we need it? */
1694 pCaps->FlipCaps.Value = 0;
1695 /* ? pCaps->FlipCaps.FlipOnVSyncWithNoWait = 1; */
1696 pCaps->SchedulingCaps.Value = 0;
1697 /* we might need it for Aero.
1698 * Setting this flag means we support DeviceContext, i.e.
1699 * DxgkDdiCreateContext and DxgkDdiDestroyContext
1700 */
1701 pCaps->SchedulingCaps.MultiEngineAware = 1;
1702 pCaps->MemoryManagementCaps.Value = 0;
1703 /** @todo this correlates with pCaps->SchedulingCaps.MultiEngineAware */
1704 pCaps->MemoryManagementCaps.PagingNode = 0;
1705 /** @todo this correlates with pCaps->SchedulingCaps.MultiEngineAware */
1706 pCaps->GpuEngineTopology.NbAsymetricProcessingNodes = VBOXWDDM_NUM_NODES;
1707#ifdef VBOX_WITH_VMSVGA
1708 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
1709 {
1710 /* The Gallium node has NodeOrdinal == 0, because:
1711 * GDI context is created with it;
1712 * we generate commands for the context;
1713 * there seems to be no easy way to distinguish which node a fence was completed for.
1714 *
1715 * GDI context is used for example for copying between D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE
1716 * and D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE.
1717 */
1718 pCaps->GpuEngineTopology.NbAsymetricProcessingNodes = 1;
1719 }
1720#endif
1721
1722 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
1723 pCaps->WDDMVersion = DXGKDDI_WDDMv1_2;
1724 }
1725 else
1726 {
1727 pCaps->WDDMVersion = DXGKDDI_WDDMv1_2;
1728 }
1729 break;
1730 }
1731 case DXGKQAITYPE_QUERYSEGMENT:
1732 {
1733 if (!g_VBoxDisplayOnly)
1734 {
1735#ifdef VBOX_WITH_VMSVGA3D_DX
1736 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA && SvgaIsDXSupported(pDevExt))
1737 {
1738 DXGK_QUERYSEGMENTOUT *pOut = (DXGK_QUERYSEGMENTOUT *)pQueryAdapterInfo->pOutputData;
1739 if (!pOut->pSegmentDescriptor)
1740 pOut->NbSegment = VBOXDX_SEGMENTS_COUNT; /* Return the number of segments. */
1741 else if (pOut->NbSegment == VBOXDX_SEGMENTS_COUNT)
1742 {
1743 DXGK_SEGMENTDESCRIPTOR *paDesc = pOut->pSegmentDescriptor;
1744 for (unsigned i = 0; i < VBOXDX_SEGMENTS_COUNT; ++i)
1745 {
1746 VBOXDXSEGMENTDESCRIPTOR desc;
1747 vmsvgaDXGetSegmentDescription(pDevExt, i, &desc);
1748 paDesc[i].CpuTranslatedAddress = desc.CpuTranslatedAddress;
1749 paDesc[i].Size = desc.Size;
1750 paDesc[i].CommitLimit = desc.Size;
1751 paDesc[i].Flags = desc.Flags;
1752 }
1753
1754 pOut->PagingBufferSegmentId = 0;
1755 pOut->PagingBufferSize = PAGE_SIZE;
1756 pOut->PagingBufferPrivateDataSize = PAGE_SIZE;
1757 }
1758 else
1759 {
1760 WARN(("NbSegment %d", pOut->NbSegment));
1761 Status = STATUS_INVALID_PARAMETER;
1762 }
1763 break;
1764 }
1765#endif
1766 /* no need for DXGK_QUERYSEGMENTIN as it contains AGP aperture info, which (AGP aperture) we do not support
1767 * DXGK_QUERYSEGMENTIN *pQsIn = (DXGK_QUERYSEGMENTIN*)pQueryAdapterInfo->pInputData; */
1768 DXGK_QUERYSEGMENTOUT *pQsOut = (DXGK_QUERYSEGMENTOUT*)pQueryAdapterInfo->pOutputData;
1769# define VBOXWDDM_SEGMENTS_COUNT 2
1770 if (!pQsOut->pSegmentDescriptor)
1771 {
1772 /* we are requested to provide the number of segments we support */
1773 pQsOut->NbSegment = VBOXWDDM_SEGMENTS_COUNT;
1774 }
1775 else if (pQsOut->NbSegment != VBOXWDDM_SEGMENTS_COUNT)
1776 {
1777 WARN(("NbSegment (%d) != 1", pQsOut->NbSegment));
1778 Status = STATUS_INVALID_PARAMETER;
1779 }
1780 else
1781 {
1782 DXGK_SEGMENTDESCRIPTOR* pDr = pQsOut->pSegmentDescriptor;
1783 /* we are requested to provide segment information */
1784 pDr->BaseAddress.QuadPart = 0;
1785 pDr->CpuTranslatedAddress = VBoxCommonFromDeviceExt(pDevExt)->phVRAM;
1786 /* make sure the size is page aligned */
1787 /** @todo need to setup VBVA buffers and adjust the mem size here */
1788 pDr->Size = vboxWddmVramCpuVisibleSegmentSize(pDevExt);
1789 pDr->NbOfBanks = 0;
1790 pDr->pBankRangeTable = 0;
1791 pDr->CommitLimit = pDr->Size;
1792 pDr->Flags.Value = 0;
1793 pDr->Flags.CpuVisible = 1;
1794
1795 ++pDr;
1796 /* create cpu-invisible segment of the same size */
1797 pDr->BaseAddress.QuadPart = 0;
1798 pDr->CpuTranslatedAddress.QuadPart = 0;
1799 /* make sure the size is page aligned */
1800 /** @todo need to setup VBVA buffers and adjust the mem size here */
1801 pDr->Size = vboxWddmVramCpuInvisibleSegmentSize(pDevExt);
1802 pDr->NbOfBanks = 0;
1803 pDr->pBankRangeTable = 0;
1804 pDr->CommitLimit = pDr->Size;
1805 pDr->Flags.Value = 0;
1806
1807 pQsOut->PagingBufferSegmentId = 0;
1808 pQsOut->PagingBufferSize = PAGE_SIZE;
1809 pQsOut->PagingBufferPrivateDataSize = PAGE_SIZE;
1810 }
1811 }
1812 else
1813 {
1814 WARN(("unsupported Type (%d)", pQueryAdapterInfo->Type));
1815 Status = STATUS_NOT_SUPPORTED;
1816 }
1817
1818 break;
1819 }
1820 case DXGKQAITYPE_UMDRIVERPRIVATE:
1821 if (!g_VBoxDisplayOnly)
1822 {
1823 if (pQueryAdapterInfo->OutputDataSize >= sizeof(VBOXWDDM_QAI))
1824 {
1825 VBOXWDDM_QAI *pQAI = (VBOXWDDM_QAI *)pQueryAdapterInfo->pOutputData;
1826 memset(pQAI, 0, sizeof(VBOXWDDM_QAI));
1827
1828 pQAI->u32Version = VBOXVIDEOIF_VERSION;
1829 pQAI->enmHwType = pDevExt->enmHwType;
1830 pQAI->u32AdapterCaps = pDevExt->f3DEnabled ? VBOXWDDM_QAI_CAP_3D : 0;
1831 pQAI->u32AdapterCaps |= VBOXWDDM_QAI_CAP_DXVA; /** @todo Fetch from registry. */
1832 if (VBoxQueryWinVersion(NULL) >= WINVERSION_7)
1833 {
1834 pQAI->u32AdapterCaps |= VBOXWDDM_QAI_CAP_WIN7;
1835 // pQAI->u32AdapterCaps |= VBOXWDDM_QAI_CAP_DXVAHD; /** @todo Fetch from registry. */
1836 }
1837
1838 static int cLoggedCaps = 0;
1839 if (cLoggedCaps < 1)
1840 {
1841 ++cLoggedCaps;
1842 LOGREL_EXACT(("WDDM: adapter capabilities 0x%08X\n", pQAI->u32AdapterCaps));
1843 }
1844
1845 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VBOX)
1846 {
1847 pQAI->u.vbox.u32VBox3DCaps = 0;
1848 }
1849#ifdef VBOX_WITH_VMSVGA
1850 else if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
1851 GaQueryInfo(pDevExt->pGa, pDevExt->enmHwType, &pQAI->u.vmsvga.HWInfo);
1852#endif
1853
1854#ifdef VBOX_WITH_VIDEOHWACCEL
1855 pQAI->cInfos = VBoxCommonFromDeviceExt(pDevExt)->cDisplays;
1856 for (uint32_t i = 0; i < pQAI->cInfos; ++i)
1857 {
1858 pQAI->aInfos[i] = pDevExt->aSources[i].Vhwa.Settings;
1859 }
1860#endif
1861 }
1862 else
1863 {
1864 WARN(("incorrect buffer size %d, expected %d", pQueryAdapterInfo->OutputDataSize, sizeof(VBOXWDDM_QAI)));
1865 Status = STATUS_BUFFER_TOO_SMALL;
1866 }
1867 }
1868 else
1869 {
1870 WARN(("unsupported Type (%d)", pQueryAdapterInfo->Type));
1871 Status = STATUS_NOT_SUPPORTED;
1872 }
1873 break;
1874
1875 case DXGKQAITYPE_QUERYSEGMENT3:
1876#ifdef VBOX_WITH_VMSVGA3D_DX
1877 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA && SvgaIsDXSupported(pDevExt))
1878 {
1879 DXGK_QUERYSEGMENTOUT3 *pOut = (DXGK_QUERYSEGMENTOUT3 *)pQueryAdapterInfo->pOutputData;
1880 if (!pOut->pSegmentDescriptor)
1881 pOut->NbSegment = VBOXDX_SEGMENTS_COUNT; /* Return the number of segments. */
1882 else if (pOut->NbSegment == VBOXDX_SEGMENTS_COUNT)
1883 {
1884 DXGK_SEGMENTDESCRIPTOR3 *paDesc = pOut->pSegmentDescriptor;
1885 for (unsigned i = 0; i < VBOXDX_SEGMENTS_COUNT; ++i)
1886 {
1887 VBOXDXSEGMENTDESCRIPTOR desc;
1888 vmsvgaDXGetSegmentDescription(pDevExt, i, &desc);
1889 paDesc[i].Flags = desc.Flags;
1890 paDesc[i].CpuTranslatedAddress = desc.CpuTranslatedAddress;
1891 paDesc[i].Size = desc.Size;
1892 paDesc[i].CommitLimit = desc.Size;
1893 }
1894
1895 pOut->PagingBufferSegmentId = 0;
1896 pOut->PagingBufferSize = PAGE_SIZE;
1897 pOut->PagingBufferPrivateDataSize = PAGE_SIZE;
1898 }
1899 else
1900 {
1901 WARN(("NbSegment %d", pOut->NbSegment));
1902 Status = STATUS_INVALID_PARAMETER;
1903 }
1904 break;
1905 }
1906#endif
1907 LOGREL(("DXGKQAITYPE_QUERYSEGMENT3 treating as unsupported!"));
1908 Status = STATUS_NOT_SUPPORTED;
1909 break;
1910
1911 default:
1912 WARN(("unsupported Type (%d)", pQueryAdapterInfo->Type));
1913 Status = STATUS_NOT_SUPPORTED;
1914 break;
1915 }
1916 LOGF(("LEAVE, context(0x%x), Status(0x%x)", hAdapter, Status));
1917 return Status;
1918}
1919
1920/**
1921 * DxgkDdiCreateDevice
1922 */
1923NTSTATUS APIENTRY DxgkDdiCreateDevice(
1924 CONST HANDLE hAdapter,
1925 DXGKARG_CREATEDEVICE* pCreateDevice)
1926{
1927 /* DxgkDdiCreateDevice should be made pageable. */
1928 PAGED_CODE();
1929
1930 LOGF(("ENTER, context(0x%x)", hAdapter));
1931 NTSTATUS Status = STATUS_SUCCESS;
1932 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
1933
1934 vboxVDbgBreakFv();
1935
1936 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)vboxWddmMemAllocZero(sizeof (VBOXWDDM_DEVICE));
1937 if (!pDevice)
1938 {
1939 WARN(("vboxWddmMemAllocZero failed for WDDM device structure"));
1940 return STATUS_NO_MEMORY;
1941 }
1942
1943 pDevice->pAdapter = pDevExt;
1944 pDevice->hDevice = pCreateDevice->hDevice;
1945
1946 pCreateDevice->hDevice = pDevice;
1947 if (pCreateDevice->Flags.SystemDevice)
1948 pDevice->enmType = VBOXWDDM_DEVICE_TYPE_SYSTEM;
1949
1950 pCreateDevice->pInfo = NULL;
1951
1952#ifdef VBOX_WITH_VMSVGA
1953 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
1954 {
1955 Status = GaDeviceCreate(pDevExt->pGa, pDevice);
1956 if (Status != STATUS_SUCCESS)
1957 {
1958 vboxWddmMemFree(pDevice);
1959 }
1960 }
1961#endif
1962
1963 LOGF(("LEAVE, context(0x%x), Status(0x%x)", hAdapter, Status));
1964
1965 return Status;
1966}
1967
1968PVBOXWDDM_RESOURCE vboxWddmResourceCreate(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_RCINFO pRcInfo)
1969{
1970 RT_NOREF(pDevExt);
1971 PVBOXWDDM_RESOURCE pResource = (PVBOXWDDM_RESOURCE)vboxWddmMemAllocZero(RT_UOFFSETOF_DYN(VBOXWDDM_RESOURCE,
1972 aAllocations[pRcInfo->cAllocInfos]));
1973 if (!pResource)
1974 {
1975 AssertFailed();
1976 return NULL;
1977 }
1978 pResource->cRefs = 1;
1979 pResource->cAllocations = pRcInfo->cAllocInfos;
1980 pResource->fFlags = pRcInfo->fFlags;
1981 pResource->RcDesc = pRcInfo->RcDesc;
1982 return pResource;
1983}
1984
1985VOID vboxWddmResourceRetain(PVBOXWDDM_RESOURCE pResource)
1986{
1987 ASMAtomicIncU32(&pResource->cRefs);
1988}
1989
1990static VOID vboxWddmResourceDestroy(PVBOXWDDM_RESOURCE pResource)
1991{
1992 vboxWddmMemFree(pResource);
1993}
1994
1995VOID vboxWddmResourceWaitDereference(PVBOXWDDM_RESOURCE pResource)
1996{
1997 vboxWddmCounterU32Wait(&pResource->cRefs, 1);
1998}
1999
2000VOID vboxWddmResourceRelease(PVBOXWDDM_RESOURCE pResource)
2001{
2002 uint32_t cRefs = ASMAtomicDecU32(&pResource->cRefs);
2003 Assert(cRefs < UINT32_MAX/2);
2004 if (!cRefs)
2005 {
2006 vboxWddmResourceDestroy(pResource);
2007 }
2008}
2009
2010void vboxWddmAllocationDeleteFromResource(PVBOXWDDM_RESOURCE pResource, PVBOXWDDM_ALLOCATION pAllocation)
2011{
2012 Assert(pAllocation->pResource == pResource);
2013 if (pResource)
2014 {
2015 Assert(&pResource->aAllocations[pAllocation->iIndex] == pAllocation);
2016 vboxWddmResourceRelease(pResource);
2017 }
2018 else
2019 {
2020 vboxWddmMemFree(pAllocation);
2021 }
2022}
2023
2024VOID vboxWddmAllocationCleanupAssignment(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAllocation)
2025{
2026 switch (pAllocation->enmType)
2027 {
2028 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE:
2029 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
2030 {
2031 if (pAllocation->bAssigned)
2032 {
2033 /** @todo do we need to notify host? */
2034 vboxWddmAssignPrimary(&pDevExt->aSources[pAllocation->AllocData.SurfDesc.VidPnSourceId], NULL, pAllocation->AllocData.SurfDesc.VidPnSourceId);
2035 }
2036 break;
2037 }
2038 default:
2039 break;
2040 }
2041}
2042
2043VOID vboxWddmAllocationCleanup(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAllocation)
2044{
2045 RT_NOREF(pDevExt);
2046 switch (pAllocation->enmType)
2047 {
2048 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE:
2049 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
2050 {
2051#if 0
2052 if (pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC)
2053 {
2054 if (pAllocation->hSharedHandle)
2055 {
2056 vboxShRcTreeRemove(pDevExt, pAllocation);
2057 }
2058 }
2059#endif
2060 break;
2061 }
2062 case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER:
2063 {
2064 break;
2065 }
2066 default:
2067 break;
2068 }
2069}
2070
2071VOID vboxWddmAllocationDestroy(PVBOXWDDM_ALLOCATION pAllocation)
2072{
2073 PAGED_CODE();
2074
2075 vboxWddmAllocationDeleteFromResource(pAllocation->pResource, pAllocation);
2076}
2077
2078PVBOXWDDM_ALLOCATION vboxWddmAllocationCreateFromResource(PVBOXWDDM_RESOURCE pResource, uint32_t iIndex)
2079{
2080 PVBOXWDDM_ALLOCATION pAllocation = NULL;
2081 if (pResource)
2082 {
2083 Assert(iIndex < pResource->cAllocations);
2084 if (iIndex < pResource->cAllocations)
2085 {
2086 pAllocation = &pResource->aAllocations[iIndex];
2087 memset(pAllocation, 0, sizeof (VBOXWDDM_ALLOCATION));
2088 }
2089 vboxWddmResourceRetain(pResource);
2090 }
2091 else
2092 pAllocation = (PVBOXWDDM_ALLOCATION)vboxWddmMemAllocZero(sizeof (VBOXWDDM_ALLOCATION));
2093
2094 if (pAllocation)
2095 {
2096 if (pResource)
2097 {
2098 pAllocation->pResource = pResource;
2099 pAllocation->iIndex = iIndex;
2100 }
2101 }
2102
2103 return pAllocation;
2104}
2105
2106NTSTATUS vboxWddmAllocationCreate(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_RESOURCE pResource, uint32_t iIndex, DXGK_ALLOCATIONINFO* pAllocationInfo)
2107{
2108 PAGED_CODE();
2109
2110 NTSTATUS Status = STATUS_SUCCESS;
2111
2112 Assert(pAllocationInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_ALLOCINFO));
2113 if (pAllocationInfo->PrivateDriverDataSize >= sizeof (VBOXWDDM_ALLOCINFO))
2114 {
2115 PVBOXWDDM_ALLOCINFO pAllocInfo = (PVBOXWDDM_ALLOCINFO)pAllocationInfo->pPrivateDriverData;
2116 PVBOXWDDM_ALLOCATION pAllocation = vboxWddmAllocationCreateFromResource(pResource, iIndex);
2117 Assert(pAllocation);
2118 if (pAllocation)
2119 {
2120 pAllocationInfo->pPrivateDriverData = NULL;
2121 pAllocationInfo->PrivateDriverDataSize = 0;
2122 pAllocationInfo->Alignment = 0;
2123 pAllocationInfo->PitchAlignedSize = 0;
2124 pAllocationInfo->HintedBank.Value = 0;
2125 pAllocationInfo->PreferredSegment.Value = 0;
2126 pAllocationInfo->SupportedReadSegmentSet = 1;
2127 pAllocationInfo->SupportedWriteSegmentSet = 1;
2128 pAllocationInfo->EvictionSegmentSet = 0;
2129 pAllocationInfo->MaximumRenamingListLength = 0;
2130 pAllocationInfo->hAllocation = pAllocation;
2131 pAllocationInfo->Flags.Value = 0;
2132 pAllocationInfo->pAllocationUsageHint = NULL;
2133 pAllocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_NORMAL;
2134
2135 pAllocation->enmType = pAllocInfo->enmType;
2136 pAllocation->AllocData.Addr.SegmentId = 0;
2137 pAllocation->AllocData.Addr.offVram = VBOXVIDEOOFFSET_VOID;
2138 pAllocation->bVisible = FALSE;
2139 pAllocation->bAssigned = FALSE;
2140 KeInitializeSpinLock(&pAllocation->OpenLock);
2141 InitializeListHead(&pAllocation->OpenList);
2142 pAllocation->CurVidPnSourceId = -1;
2143
2144 switch (pAllocInfo->enmType)
2145 {
2146 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE:
2147 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
2148 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE:
2149 case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE:
2150 {
2151 pAllocation->fRcFlags = pAllocInfo->fFlags;
2152 pAllocation->AllocData.SurfDesc = pAllocInfo->SurfDesc;
2153 pAllocation->AllocData.hostID = pAllocInfo->hostID;
2154
2155 pAllocationInfo->Size = pAllocInfo->SurfDesc.cbSize;
2156
2157 switch (pAllocInfo->enmType)
2158 {
2159 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE:
2160 break;
2161 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
2162#ifdef VBOX_WITH_VIDEOHWACCEL
2163 if (pAllocInfo->fFlags.Overlay)
2164 {
2165 /* actually we can not "properly" issue create overlay commands to the host here
2166 * because we do not know source VidPn id here, i.e.
2167 * the primary which is supposed to be overlayed,
2168 * however we need to get some info like pitch & size from the host here */
2169 int rc = vboxVhwaHlpGetSurfInfo(pDevExt, pAllocation);
2170 AssertRC(rc);
2171 if (RT_SUCCESS(rc))
2172 {
2173 pAllocationInfo->Flags.Overlay = 1;
2174 pAllocationInfo->Flags.CpuVisible = 1;
2175 pAllocationInfo->Size = pAllocation->AllocData.SurfDesc.cbSize;
2176
2177 pAllocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_HIGH;
2178 }
2179 else
2180 Status = STATUS_UNSUCCESSFUL;
2181 }
2182 else
2183#endif
2184 {
2185 RT_NOREF(pDevExt);
2186
2187 Assert(pAllocation->AllocData.SurfDesc.bpp);
2188 Assert(pAllocation->AllocData.SurfDesc.pitch);
2189 Assert(pAllocation->AllocData.SurfDesc.cbSize);
2190
2191 /*
2192 * Mark the allocation as visible to the CPU so we can
2193 * lock it in the user mode driver for SYSTEM pool allocations.
2194 * See @bugref{8040} for further information.
2195 */
2196 if (!pAllocInfo->fFlags.SharedResource && !pAllocInfo->hostID)
2197 pAllocationInfo->Flags.CpuVisible = 1;
2198
2199 if (pAllocInfo->fFlags.SharedResource)
2200 {
2201 pAllocation->hSharedHandle = (HANDLE)pAllocInfo->hSharedHandle;
2202#if 0
2203 if (pAllocation->hSharedHandle)
2204 {
2205 vboxShRcTreePut(pDevExt, pAllocation);
2206 }
2207#endif
2208 }
2209
2210#if 0
2211 /* Allocation from the CPU invisible second segment does not
2212 * work apparently and actually fails on Vista.
2213 *
2214 * @todo Find out what exactly is wrong.
2215 */
2216// if (pAllocInfo->hostID)
2217 {
2218 pAllocationInfo->SupportedReadSegmentSet = 2;
2219 pAllocationInfo->SupportedWriteSegmentSet = 2;
2220 }
2221#endif
2222 }
2223 break;
2224 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE:
2225 case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE:
2226 pAllocationInfo->Flags.CpuVisible = 1;
2227 break;
2228 default: AssertFailedBreak(); /* Shut up MSC.*/
2229 }
2230
2231 if (Status == STATUS_SUCCESS)
2232 {
2233 pAllocation->UsageHint.Version = 0;
2234 pAllocation->UsageHint.v1.Flags.Value = 0;
2235 pAllocation->UsageHint.v1.Format = pAllocInfo->SurfDesc.format;
2236 pAllocation->UsageHint.v1.SwizzledFormat = 0;
2237 pAllocation->UsageHint.v1.ByteOffset = 0;
2238 pAllocation->UsageHint.v1.Width = pAllocation->AllocData.SurfDesc.width;
2239 pAllocation->UsageHint.v1.Height = pAllocation->AllocData.SurfDesc.height;
2240 pAllocation->UsageHint.v1.Pitch = pAllocation->AllocData.SurfDesc.pitch;
2241 pAllocation->UsageHint.v1.Depth = 0;
2242 pAllocation->UsageHint.v1.SlicePitch = 0;
2243
2244 Assert(!pAllocationInfo->pAllocationUsageHint);
2245 pAllocationInfo->pAllocationUsageHint = &pAllocation->UsageHint;
2246 }
2247
2248 break;
2249 }
2250 case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER:
2251 {
2252 pAllocationInfo->Size = pAllocInfo->cbBuffer;
2253 pAllocation->fUhgsmiType = pAllocInfo->fUhgsmiType;
2254 pAllocation->AllocData.SurfDesc.cbSize = pAllocInfo->cbBuffer;
2255 pAllocationInfo->Flags.CpuVisible = 1;
2256// pAllocationInfo->Flags.SynchronousPaging = 1;
2257 pAllocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_MAXIMUM;
2258 break;
2259 }
2260
2261 default:
2262 LOGREL(("ERROR: invalid alloc info type(%d)", pAllocInfo->enmType));
2263 AssertBreakpoint();
2264 Status = STATUS_INVALID_PARAMETER;
2265 break;
2266
2267 }
2268
2269 if (Status != STATUS_SUCCESS)
2270 vboxWddmAllocationDeleteFromResource(pResource, pAllocation);
2271 }
2272 else
2273 {
2274 LOGREL(("ERROR: failed to create allocation description"));
2275 Status = STATUS_NO_MEMORY;
2276 }
2277
2278 }
2279 else
2280 {
2281 LOGREL(("ERROR: PrivateDriverDataSize(%d) less than header size(%d)", pAllocationInfo->PrivateDriverDataSize, sizeof (VBOXWDDM_ALLOCINFO)));
2282 Status = STATUS_INVALID_PARAMETER;
2283 }
2284
2285 return Status;
2286}
2287
2288NTSTATUS APIENTRY DxgkDdiCreateAllocation(
2289 CONST HANDLE hAdapter,
2290 DXGKARG_CREATEALLOCATION* pCreateAllocation)
2291{
2292 /* DxgkDdiCreateAllocation should be made pageable. */
2293 PAGED_CODE();
2294
2295 LOGF(("ENTER, context(0x%x)", hAdapter));
2296
2297 vboxVDbgBreakFv();
2298
2299#ifdef VBOX_WITH_VMSVGA3D_DX
2300 /* The driver distinguished between the legacy and the new D3D(DX) requests by checking the size. */
2301 AssertCompile(sizeof(VBOXDXALLOCATIONDESC) != sizeof(VBOXWDDM_ALLOCINFO));
2302
2303 /* Check if this is a request from the new D3D driver. */
2304 if ( pCreateAllocation->PrivateDriverDataSize == 0
2305 && pCreateAllocation->NumAllocations == 1
2306 && pCreateAllocation->pAllocationInfo[0].PrivateDriverDataSize == sizeof(VBOXDXALLOCATIONDESC))
2307 return DxgkDdiDXCreateAllocation(hAdapter, pCreateAllocation);
2308#endif
2309
2310 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
2311 NTSTATUS Status = STATUS_SUCCESS;
2312 PVBOXWDDM_RESOURCE pResource = NULL;
2313
2314 if (pCreateAllocation->PrivateDriverDataSize)
2315 {
2316 Assert(pCreateAllocation->PrivateDriverDataSize == sizeof (VBOXWDDM_RCINFO));
2317 Assert(pCreateAllocation->pPrivateDriverData);
2318 if (pCreateAllocation->PrivateDriverDataSize < sizeof (VBOXWDDM_RCINFO))
2319 {
2320 WARN(("invalid private data size (%d)", pCreateAllocation->PrivateDriverDataSize));
2321 return STATUS_INVALID_PARAMETER;
2322 }
2323
2324 PVBOXWDDM_RCINFO pRcInfo = (PVBOXWDDM_RCINFO)pCreateAllocation->pPrivateDriverData;
2325// Assert(pRcInfo->RcDesc.VidPnSourceId < VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
2326 if (pRcInfo->cAllocInfos != pCreateAllocation->NumAllocations)
2327 {
2328 WARN(("invalid number of allocations passed in, (%d), expected (%d)", pRcInfo->cAllocInfos, pCreateAllocation->NumAllocations));
2329 return STATUS_INVALID_PARAMETER;
2330 }
2331
2332 /* a check to ensure we do not get the allocation size which is too big to overflow the 32bit value */
2333 if (VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXWDDM_RESOURCE, aAllocations) < pRcInfo->cAllocInfos)
2334 {
2335 WARN(("number of allocations passed too big (%d), max is (%d)", pRcInfo->cAllocInfos, VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXWDDM_RESOURCE, aAllocations)));
2336 return STATUS_INVALID_PARAMETER;
2337 }
2338
2339 pResource = (PVBOXWDDM_RESOURCE)vboxWddmMemAllocZero(RT_UOFFSETOF_DYN(VBOXWDDM_RESOURCE, aAllocations[pRcInfo->cAllocInfos]));
2340 if (!pResource)
2341 {
2342 WARN(("vboxWddmMemAllocZero failed for (%d) allocations", pRcInfo->cAllocInfos));
2343 return STATUS_NO_MEMORY;
2344 }
2345
2346 pResource->cRefs = 1;
2347 pResource->cAllocations = pRcInfo->cAllocInfos;
2348 pResource->fFlags = pRcInfo->fFlags;
2349 pResource->RcDesc = pRcInfo->RcDesc;
2350 }
2351
2352
2353 for (UINT i = 0; i < pCreateAllocation->NumAllocations; ++i)
2354 {
2355 Status = vboxWddmAllocationCreate(pDevExt, pResource, i, &pCreateAllocation->pAllocationInfo[i]);
2356 if (Status != STATUS_SUCCESS)
2357 {
2358 WARN(("vboxWddmAllocationCreate(%d) failed, Status(0x%x)", i, Status));
2359 /* note: i-th allocation is expected to be cleared in a fail handling code above */
2360 for (UINT j = 0; j < i; ++j)
2361 {
2362 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pCreateAllocation->pAllocationInfo[j].hAllocation;
2363 vboxWddmAllocationCleanup(pDevExt, pAllocation);
2364 vboxWddmAllocationDestroy(pAllocation);
2365 }
2366 break;
2367 }
2368 }
2369
2370 if (Status == STATUS_SUCCESS)
2371 {
2372 pCreateAllocation->hResource = pResource;
2373 }
2374 else
2375 {
2376 if (pResource)
2377 vboxWddmResourceRelease(pResource);
2378 }
2379
2380 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
2381
2382 return Status;
2383}
2384
2385NTSTATUS
2386APIENTRY
2387DxgkDdiDestroyAllocation(
2388 CONST HANDLE hAdapter,
2389 CONST DXGKARG_DESTROYALLOCATION* pDestroyAllocation)
2390{
2391 /* DxgkDdiDestroyAllocation should be made pageable. */
2392 PAGED_CODE();
2393
2394 LOGF(("ENTER, context(0x%x)", hAdapter));
2395
2396 vboxVDbgBreakFv();
2397
2398 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
2399
2400 for (UINT i = 0; i < pDestroyAllocation->NumAllocations; ++i)
2401 {
2402 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pDestroyAllocation->pAllocationList[0];
2403 if (pAllocation->CurVidPnSourceId != -1)
2404 {
2405 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAllocation->CurVidPnSourceId];
2406 vboxWddmAssignPrimary(pSource, NULL, pAllocation->CurVidPnSourceId);
2407 }
2408 }
2409
2410#ifdef VBOX_WITH_VMSVGA3D_DX
2411 /* Check if this is a request from the D3D driver. */
2412 if (pDestroyAllocation->NumAllocations >= 1)
2413 {
2414 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pDestroyAllocation->pAllocationList[0];
2415 if (pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_D3D)
2416 return DxgkDdiDXDestroyAllocation(hAdapter, pDestroyAllocation);
2417 }
2418#endif
2419
2420 NTSTATUS Status = STATUS_SUCCESS;
2421
2422 PVBOXWDDM_RESOURCE pRc = (PVBOXWDDM_RESOURCE)pDestroyAllocation->hResource;
2423 if (pRc)
2424 {
2425 Assert(pRc->cAllocations == pDestroyAllocation->NumAllocations);
2426 }
2427
2428 for (UINT i = 0; i < pDestroyAllocation->NumAllocations; ++i)
2429 {
2430 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pDestroyAllocation->pAllocationList[i];
2431 Assert(pAlloc->pResource == pRc);
2432 vboxWddmAllocationCleanupAssignment(pDevExt, pAlloc);
2433 /* wait for all current allocation-related ops are completed */
2434 vboxWddmAllocationCleanup(pDevExt, pAlloc);
2435 vboxWddmAllocationDestroy(pAlloc);
2436 }
2437
2438 if (pRc)
2439 {
2440 /* wait for all current resource-related ops are completed */
2441 vboxWddmResourceWaitDereference(pRc);
2442 vboxWddmResourceRelease(pRc);
2443 }
2444
2445 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
2446
2447 return Status;
2448}
2449
2450/**
2451 * DxgkDdiDescribeAllocation
2452 */
2453NTSTATUS
2454APIENTRY
2455DxgkDdiDescribeAllocation(
2456 CONST HANDLE hAdapter,
2457 DXGKARG_DESCRIBEALLOCATION* pDescribeAllocation)
2458{
2459 RT_NOREF(hAdapter);
2460// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2461
2462 vboxVDbgBreakFv();
2463
2464 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pDescribeAllocation->hAllocation;
2465#ifdef VBOX_WITH_VMSVGA3D_DX
2466 /* Check if this is a request from the D3D driver. */
2467 if (pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_D3D)
2468 return DxgkDdiDXDescribeAllocation(hAdapter, pDescribeAllocation);
2469#endif
2470 pDescribeAllocation->Width = pAllocation->AllocData.SurfDesc.width;
2471 pDescribeAllocation->Height = pAllocation->AllocData.SurfDesc.height;
2472 pDescribeAllocation->Format = pAllocation->AllocData.SurfDesc.format;
2473 memset (&pDescribeAllocation->MultisampleMethod, 0, sizeof (pDescribeAllocation->MultisampleMethod));
2474 pDescribeAllocation->RefreshRate.Numerator = g_RefreshRate * 1000;
2475 pDescribeAllocation->RefreshRate.Denominator = 1000;
2476 pDescribeAllocation->PrivateDriverFormatAttribute = 0;
2477
2478// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2479
2480 return STATUS_SUCCESS;
2481}
2482
2483/**
2484 * DxgkDdiGetStandardAllocationDriverData
2485 */
2486NTSTATUS
2487APIENTRY
2488DxgkDdiGetStandardAllocationDriverData(
2489 CONST HANDLE hAdapter,
2490 DXGKARG_GETSTANDARDALLOCATIONDRIVERDATA* pGetStandardAllocationDriverData)
2491{
2492 RT_NOREF(hAdapter);
2493 /* DxgkDdiGetStandardAllocationDriverData should be made pageable. */
2494 PAGED_CODE();
2495
2496 LOGF(("ENTER, context(0x%x)", hAdapter));
2497
2498 vboxVDbgBreakFv();
2499
2500 NTSTATUS Status = STATUS_SUCCESS;
2501 PVBOXWDDM_ALLOCINFO pAllocInfo = NULL;
2502
2503 switch (pGetStandardAllocationDriverData->StandardAllocationType)
2504 {
2505 case D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE:
2506 {
2507 LOGF(("D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE"));
2508 if(pGetStandardAllocationDriverData->pAllocationPrivateDriverData)
2509 {
2510 pAllocInfo = (PVBOXWDDM_ALLOCINFO)pGetStandardAllocationDriverData->pAllocationPrivateDriverData;
2511 memset (pAllocInfo, 0, sizeof (VBOXWDDM_ALLOCINFO));
2512 pAllocInfo->enmType = VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE;
2513 pAllocInfo->SurfDesc.width = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Width;
2514 pAllocInfo->SurfDesc.height = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Height;
2515 pAllocInfo->SurfDesc.format = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Format;
2516 pAllocInfo->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pAllocInfo->SurfDesc.format);
2517 pAllocInfo->SurfDesc.pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Width, pAllocInfo->SurfDesc.format);
2518 pAllocInfo->SurfDesc.cbSize = vboxWddmCalcSize(pAllocInfo->SurfDesc.pitch, pAllocInfo->SurfDesc.height, pAllocInfo->SurfDesc.format);
2519 pAllocInfo->SurfDesc.depth = 0;
2520 pAllocInfo->SurfDesc.slicePitch = 0;
2521 pAllocInfo->SurfDesc.RefreshRate = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->RefreshRate;
2522 pAllocInfo->SurfDesc.VidPnSourceId = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->VidPnSourceId;
2523 }
2524 pGetStandardAllocationDriverData->AllocationPrivateDriverDataSize = sizeof (VBOXWDDM_ALLOCINFO);
2525
2526 pGetStandardAllocationDriverData->ResourcePrivateDriverDataSize = 0;
2527 break;
2528 }
2529 case D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE:
2530 {
2531 LOGF(("D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE"));
2532 UINT bpp = vboxWddmCalcBitsPerPixel(pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format);
2533 Assert(bpp);
2534 if (bpp != 0)
2535 {
2536 UINT Pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Width, pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format);
2537 pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Pitch = Pitch;
2538
2539 /** @todo need [d/q]word align?? */
2540
2541 if (pGetStandardAllocationDriverData->pAllocationPrivateDriverData)
2542 {
2543 pAllocInfo = (PVBOXWDDM_ALLOCINFO)pGetStandardAllocationDriverData->pAllocationPrivateDriverData;
2544 pAllocInfo->enmType = VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE;
2545 pAllocInfo->SurfDesc.width = pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Width;
2546 pAllocInfo->SurfDesc.height = pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Height;
2547 pAllocInfo->SurfDesc.format = pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format;
2548 pAllocInfo->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pAllocInfo->SurfDesc.format);
2549 pAllocInfo->SurfDesc.pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Width, pAllocInfo->SurfDesc.format);
2550 pAllocInfo->SurfDesc.cbSize = vboxWddmCalcSize(pAllocInfo->SurfDesc.pitch, pAllocInfo->SurfDesc.height, pAllocInfo->SurfDesc.format);
2551 pAllocInfo->SurfDesc.depth = 0;
2552 pAllocInfo->SurfDesc.slicePitch = 0;
2553 pAllocInfo->SurfDesc.RefreshRate.Numerator = 0;
2554 pAllocInfo->SurfDesc.RefreshRate.Denominator = 1000;
2555 pAllocInfo->SurfDesc.VidPnSourceId = D3DDDI_ID_UNINITIALIZED;
2556
2557 pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Pitch = pAllocInfo->SurfDesc.pitch;
2558 }
2559 pGetStandardAllocationDriverData->AllocationPrivateDriverDataSize = sizeof (VBOXWDDM_ALLOCINFO);
2560
2561 pGetStandardAllocationDriverData->ResourcePrivateDriverDataSize = 0;
2562 }
2563 else
2564 {
2565 LOGREL(("Invalid format (%d)", pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format));
2566 Status = STATUS_INVALID_PARAMETER;
2567 }
2568 break;
2569 }
2570 case D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE:
2571 {
2572 LOGF(("D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE"));
2573 if(pGetStandardAllocationDriverData->pAllocationPrivateDriverData)
2574 {
2575 pAllocInfo = (PVBOXWDDM_ALLOCINFO)pGetStandardAllocationDriverData->pAllocationPrivateDriverData;
2576 pAllocInfo->enmType = VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE;
2577 pAllocInfo->SurfDesc.width = pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Width;
2578 pAllocInfo->SurfDesc.height = pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Height;
2579 pAllocInfo->SurfDesc.format = D3DDDIFMT_X8R8G8B8; /* staging has always always D3DDDIFMT_X8R8G8B8 */
2580 pAllocInfo->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pAllocInfo->SurfDesc.format);
2581 pAllocInfo->SurfDesc.pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Width, pAllocInfo->SurfDesc.format);
2582 pAllocInfo->SurfDesc.cbSize = vboxWddmCalcSize(pAllocInfo->SurfDesc.pitch, pAllocInfo->SurfDesc.height, pAllocInfo->SurfDesc.format);
2583 pAllocInfo->SurfDesc.depth = 0;
2584 pAllocInfo->SurfDesc.slicePitch = 0;
2585 pAllocInfo->SurfDesc.RefreshRate.Numerator = 0;
2586 pAllocInfo->SurfDesc.RefreshRate.Denominator = 1000;
2587 pAllocInfo->SurfDesc.VidPnSourceId = D3DDDI_ID_UNINITIALIZED;
2588
2589 pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Pitch = pAllocInfo->SurfDesc.pitch;
2590 }
2591 pGetStandardAllocationDriverData->AllocationPrivateDriverDataSize = sizeof (VBOXWDDM_ALLOCINFO);
2592
2593 pGetStandardAllocationDriverData->ResourcePrivateDriverDataSize = 0;
2594 break;
2595 }
2596//#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN7)
2597// case D3DKMDT_STANDARDALLOCATION_GDISURFACE:
2598//# error port to Win7 DDI
2599// break;
2600//#endif
2601 default:
2602 LOGREL(("Invalid allocation type (%d)", pGetStandardAllocationDriverData->StandardAllocationType));
2603 Status = STATUS_INVALID_PARAMETER;
2604 break;
2605 }
2606
2607 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
2608
2609 return Status;
2610}
2611
2612NTSTATUS
2613APIENTRY
2614DxgkDdiAcquireSwizzlingRange(
2615 CONST HANDLE hAdapter,
2616 DXGKARG_ACQUIRESWIZZLINGRANGE* pAcquireSwizzlingRange)
2617{
2618 RT_NOREF(hAdapter, pAcquireSwizzlingRange);
2619 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2620
2621 AssertBreakpoint();
2622
2623 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2624
2625 return STATUS_SUCCESS;
2626}
2627
2628NTSTATUS
2629APIENTRY
2630DxgkDdiReleaseSwizzlingRange(
2631 CONST HANDLE hAdapter,
2632 CONST DXGKARG_RELEASESWIZZLINGRANGE* pReleaseSwizzlingRange)
2633{
2634 RT_NOREF(hAdapter, pReleaseSwizzlingRange);
2635 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2636
2637 AssertBreakpoint();
2638
2639 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2640
2641 return STATUS_SUCCESS;
2642}
2643
2644typedef struct VBOXWDDM_CALL_ISR
2645{
2646 PVBOXMP_DEVEXT pDevExt;
2647 ULONG MessageNumber;
2648} VBOXWDDM_CALL_ISR, *PVBOXWDDM_CALL_ISR;
2649
2650static BOOLEAN vboxWddmCallIsrCb(PVOID Context)
2651{
2652 PVBOXWDDM_CALL_ISR pdc = (PVBOXWDDM_CALL_ISR)Context;
2653 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
2654 if (pDevExt->fCmdVbvaEnabled)
2655 {
2656#ifdef DEBUG_sunlover
2657 /** @todo Remove VBOX_WITH_VIDEOHWACCEL code, because the host does not support it anymore. */
2658 AssertFailed(); /* Should not be here, because this is not used with 3D gallium driver. */
2659#endif
2660 return FALSE;
2661 }
2662 return DxgkDdiInterruptRoutineLegacy(pDevExt, pdc->MessageNumber);
2663}
2664
2665NTSTATUS vboxWddmCallIsr(PVBOXMP_DEVEXT pDevExt)
2666{
2667 VBOXWDDM_CALL_ISR context;
2668 context.pDevExt = pDevExt;
2669 context.MessageNumber = 0;
2670 BOOLEAN bRet;
2671 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
2672 pDevExt->u.primary.DxgkInterface.DeviceHandle,
2673 vboxWddmCallIsrCb,
2674 &context,
2675 0, /* IN ULONG MessageNumber */
2676 &bRet);
2677 AssertNtStatusSuccess(Status);
2678 return Status;
2679}
2680
2681
2682NTSTATUS
2683APIENTRY
2684DxgkDdiSetPalette(
2685 CONST HANDLE hAdapter,
2686 CONST DXGKARG_SETPALETTE* pSetPalette
2687 )
2688{
2689 RT_NOREF(hAdapter, pSetPalette);
2690 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2691
2692 AssertBreakpoint();
2693 /** @todo fixme: implement */
2694
2695 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2696
2697 return STATUS_SUCCESS;
2698}
2699
2700/** Find which area of a 32 bit mouse pointer bitmap is actually used.
2701 * Zero pixels on the right and the bottom of the bitmap are considered unused.
2702 *
2703 * @param pPixels The bitmap.
2704 * @param Pitch The bitmap scanline size in bytes.
2705 * @param Width The bitmap width.
2706 * @param Height The bitmap height.
2707 * @param piMaxFilledPixel Where to store the maximum index of non-zero pixel within a scanline.
2708 * @param piMaxFilledScanline Where to store the zero based index of the last scanline with non-zero pixels.
2709 */
2710static void vboxWddmPointerFindDimensionsColor(void const *pPixels, UINT Pitch, UINT Width, UINT Height,
2711 LONG *piMaxFilledPixel, LONG *piMaxFilledScanline)
2712{
2713 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2714 * Exclude zero pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2715 */
2716 DWORD const *pdwScanline = (DWORD *)pPixels;
2717 LONG iMaxFilledScanline = -1;
2718 LONG iMaxFilledPixel = -1;
2719 for (ULONG y = 0; y < Height; ++y)
2720 {
2721 LONG iLastFilledPixel = -1;
2722 for (ULONG x = 0; x < Width; ++x)
2723 {
2724 if (pdwScanline[x])
2725 iLastFilledPixel = x;
2726 }
2727
2728 iMaxFilledPixel = RT_MAX(iMaxFilledPixel, iLastFilledPixel);
2729
2730 if (iLastFilledPixel >= 0)
2731 {
2732 /* Scanline contains non-zero pixels. */
2733 iMaxFilledScanline = y;
2734 }
2735
2736 pdwScanline = (DWORD *)((uint8_t *)pdwScanline + Pitch);
2737 }
2738
2739 *piMaxFilledPixel = iMaxFilledPixel;
2740 *piMaxFilledScanline = iMaxFilledScanline;
2741}
2742
2743/** Find which area of a 1 bit AND/XOR mask bitmap is actually used, i.e. filled with actual data.
2744 * For the AND mask the bytes with a value 0xff on the right and the bottom of the bitmap are considered unused.
2745 * For the XOR mask the blank value is 0x00.
2746 *
2747 * @param pPixels The 1bit bitmap.
2748 * @param Pitch The 1bit bitmap scanline size in bytes.
2749 * @param Width The bitmap width.
2750 * @param Height The bitmap height.
2751 * @param Blank The value of the unused bytes in the supplied bitmap.
2752 * @param piMaxFilledPixel Where to store the maximum index of a filled pixel within a scanline.
2753 * @param piMaxFilledScanline Where to store the zero based index of the last scanline with filled pixels.
2754 */
2755static void vboxWddmPointerFindDimensionsMono(void const *pPixels, UINT Pitch, UINT Width, UINT Height, BYTE Blank,
2756 LONG *piMaxFilledPixel, LONG *piMaxFilledScanline)
2757{
2758 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2759 * Exclude the blank pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2760 */
2761 BYTE const *pbScanline = (BYTE *)pPixels;
2762 LONG iMaxFilledScanline = -1;
2763 LONG iMaxFilledByte = -1;
2764 for (ULONG y = 0; y < Height; ++y)
2765 {
2766 LONG iLastFilledByte = -1;
2767 for (ULONG x = 0; x < Width / 8; ++x)
2768 {
2769 if (pbScanline[x] != Blank)
2770 iLastFilledByte = x;
2771 }
2772
2773 iMaxFilledByte = RT_MAX(iMaxFilledByte, iLastFilledByte);
2774
2775 if (iLastFilledByte >= 0)
2776 {
2777 /* Scanline contains filled pixels. */
2778 iMaxFilledScanline = y;
2779 }
2780
2781 pbScanline += Pitch;
2782 }
2783
2784 *piMaxFilledPixel = iMaxFilledByte * 8;
2785 *piMaxFilledScanline = iMaxFilledScanline;
2786}
2787
2788/** Adjust the width and the height of the mouse pointer bitmap.
2789 * See comments in the function for the adjustment criteria.
2790 *
2791 * @param iMaxX The index of the rightmost pixel which we want to keep.
2792 * @param iMaxY The index of the bottom-most pixel which we want to keep.
2793 * @param XHot The mouse pointer hot spot.
2794 * @param YHot The mouse pointer hot spot.
2795 * @param pWidth Where to store the bitmap width.
2796 * @param pHeight Where to store the bitmap height.
2797 */
2798static void vboxWddmPointerAdjustDimensions(LONG iMaxX, LONG iMaxY, UINT XHot, UINT YHot,
2799 ULONG *pWidth, ULONG *pHeight)
2800{
2801 /* Both input parameters are zero based indexes, add 1 to get a width and a height. */
2802 ULONG W = iMaxX + 1;
2803 ULONG H = iMaxY + 1;
2804
2805 /* Always include the hotspot point. */
2806 W = RT_MAX(XHot, W);
2807 H = RT_MAX(YHot, H);
2808
2809 /* Align to 8 pixels, because the XOR/AND pointers are aligned like that.
2810 * The AND mask has one bit per pixel with 8 bits per byte.
2811 * In case the host can't deal with unaligned data.
2812 */
2813 W = RT_ALIGN_T(W, 8, ULONG);
2814 H = RT_ALIGN_T(H, 8, ULONG);
2815
2816 /* Do not send bitmaps with zero dimensions. Actually make the min size 32x32. */
2817 W = RT_MAX(32, W);
2818 H = RT_MAX(32, H);
2819
2820 /* Make it square. Some hosts are known to require square pointers. */
2821 W = RT_MAX(W, H);
2822 H = W;
2823
2824 /* Do not exceed the supported size.
2825 * Actually this should not be necessary because Windows never creates such pointers.
2826 */
2827 W = RT_MIN(W, VBOXWDDM_C_POINTER_MAX_WIDTH);
2828 H = RT_MIN(H, VBOXWDDM_C_POINTER_MAX_HEIGHT);
2829
2830 *pWidth = W;
2831 *pHeight = H;
2832}
2833
2834BOOL vboxWddmPointerCopyColorData(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVIDEO_POINTER_ATTRIBUTES pPointerAttributes,
2835 bool fDwordAlignScanlines)
2836{
2837 ULONG srcMaskW, srcMaskH;
2838 ULONG dstBytesPerLine;
2839 ULONG x, y;
2840 BYTE *pSrc, *pDst, bit;
2841
2842 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2843 * Exclude zero pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2844 */
2845 LONG iMaxFilledPixel;
2846 LONG iMaxFilledScanline;
2847 vboxWddmPointerFindDimensionsColor(pSetPointerShape->pPixels, pSetPointerShape->Pitch,
2848 pSetPointerShape->Width, pSetPointerShape->Height,
2849 &iMaxFilledPixel, &iMaxFilledScanline);
2850
2851 vboxWddmPointerAdjustDimensions(iMaxFilledPixel, iMaxFilledScanline,
2852 pSetPointerShape->XHot, pSetPointerShape->YHot,
2853 &srcMaskW, &srcMaskH);
2854
2855 pPointerAttributes->Width = srcMaskW;
2856 pPointerAttributes->Height = srcMaskH;
2857 pPointerAttributes->WidthInBytes = pPointerAttributes->Width * 4;
2858
2859 /* cnstruct and mask from alpha color channel */
2860 pSrc = (PBYTE)pSetPointerShape->pPixels;
2861 pDst = pPointerAttributes->Pixels;
2862 dstBytesPerLine = (pPointerAttributes->Width+7)/8;
2863 if (fDwordAlignScanlines)
2864 dstBytesPerLine = RT_ALIGN_T(dstBytesPerLine, 4, ULONG);
2865
2866 /* sanity check */
2867 uint32_t cbData = RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG)+
2868 pPointerAttributes->Height*pPointerAttributes->WidthInBytes;
2869 uint32_t cbPointerAttributes = RT_UOFFSETOF_DYN(VIDEO_POINTER_ATTRIBUTES, Pixels[cbData]);
2870 Assert(VBOXWDDM_POINTER_ATTRIBUTES_SIZE >= cbPointerAttributes);
2871 if (VBOXWDDM_POINTER_ATTRIBUTES_SIZE < cbPointerAttributes)
2872 {
2873 LOGREL(("VBOXWDDM_POINTER_ATTRIBUTES_SIZE(%d) < cbPointerAttributes(%d)", VBOXWDDM_POINTER_ATTRIBUTES_SIZE, cbPointerAttributes));
2874 return FALSE;
2875 }
2876
2877 memset(pDst, 0xFF, dstBytesPerLine*pPointerAttributes->Height);
2878 for (y=0; y<pPointerAttributes->Height; ++y)
2879 {
2880 for (x=0, bit=7; x<pPointerAttributes->Width; ++x, --bit)
2881 {
2882 if (0xFF==bit) bit=7;
2883
2884 if (pSrc[y*pSetPointerShape->Pitch + x*4 + 3] > 0x7F)
2885 {
2886 pDst[y*dstBytesPerLine + x/8] &= ~RT_BIT(bit);
2887 }
2888 }
2889 }
2890
2891 /* copy 32bpp to XOR DIB, it start in pPointerAttributes->Pixels should be 4bytes aligned */
2892 pSrc = (BYTE*)pSetPointerShape->pPixels;
2893 pDst = pPointerAttributes->Pixels + RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG);
2894 dstBytesPerLine = pPointerAttributes->Width * 4;
2895
2896 for (y=0; y<pPointerAttributes->Height; ++y)
2897 {
2898 memcpy(pDst+y*dstBytesPerLine, pSrc+y*pSetPointerShape->Pitch, dstBytesPerLine);
2899 }
2900
2901 return TRUE;
2902}
2903
2904BOOL vboxWddmPointerCopyMonoData(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVIDEO_POINTER_ATTRIBUTES pPointerAttributes,
2905 bool fDwordAlignScanlines)
2906{
2907 ULONG srcMaskW, srcMaskH;
2908 ULONG dstBytesPerLine;
2909 ULONG x, y;
2910 BYTE *pSrc, *pDst, bit;
2911
2912 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2913 * Exclude unused pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2914 */
2915 LONG iMaxFilledPixelAND;
2916 LONG iMaxFilledScanlineAND;
2917 vboxWddmPointerFindDimensionsMono(pSetPointerShape->pPixels, pSetPointerShape->Pitch,
2918 pSetPointerShape->Width, pSetPointerShape->Height, 0xff,
2919 &iMaxFilledPixelAND, &iMaxFilledScanlineAND);
2920
2921 LONG iMaxFilledPixelXOR;
2922 LONG iMaxFilledScanlineXOR;
2923 vboxWddmPointerFindDimensionsMono((BYTE *)pSetPointerShape->pPixels + pSetPointerShape->Height * pSetPointerShape->Pitch,
2924 pSetPointerShape->Pitch,
2925 pSetPointerShape->Width, pSetPointerShape->Height, 0x00,
2926 &iMaxFilledPixelXOR, &iMaxFilledScanlineXOR);
2927
2928 LONG iMaxFilledPixel = RT_MAX(iMaxFilledPixelAND, iMaxFilledPixelXOR);
2929 LONG iMaxFilledScanline = RT_MAX(iMaxFilledScanlineAND, iMaxFilledScanlineXOR);
2930
2931 vboxWddmPointerAdjustDimensions(iMaxFilledPixel, iMaxFilledScanline,
2932 pSetPointerShape->XHot, pSetPointerShape->YHot,
2933 &srcMaskW, &srcMaskH);
2934
2935 pPointerAttributes->Width = srcMaskW;
2936 pPointerAttributes->Height = srcMaskH;
2937 pPointerAttributes->WidthInBytes = pPointerAttributes->Width * 4;
2938
2939 /* copy AND mask */
2940 pSrc = (PBYTE)pSetPointerShape->pPixels;
2941 pDst = pPointerAttributes->Pixels;
2942 dstBytesPerLine = (pPointerAttributes->Width+7)/8;
2943 if (fDwordAlignScanlines)
2944 dstBytesPerLine = RT_ALIGN_T(dstBytesPerLine, 4, ULONG);
2945
2946 for (y=0; y<pPointerAttributes->Height; ++y)
2947 {
2948 memcpy(pDst+y*dstBytesPerLine, pSrc+y*pSetPointerShape->Pitch, dstBytesPerLine);
2949 }
2950
2951 /* convert XOR mask to RGB0 DIB, it start in pPointerAttributes->Pixels should be 4bytes aligned */
2952 pSrc = (BYTE*)pSetPointerShape->pPixels + pSetPointerShape->Height*pSetPointerShape->Pitch;
2953 pDst = pPointerAttributes->Pixels + RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG);
2954 dstBytesPerLine = pPointerAttributes->Width * 4;
2955
2956 for (y=0; y<pPointerAttributes->Height; ++y)
2957 {
2958 for (x=0, bit=7; x<pPointerAttributes->Width; ++x, --bit)
2959 {
2960 if (0xFF==bit) bit=7;
2961
2962 *(ULONG*)&pDst[y*dstBytesPerLine+x*4] = (pSrc[y*pSetPointerShape->Pitch+x/8] & RT_BIT(bit)) ? 0x00FFFFFF : 0;
2963 }
2964 }
2965
2966 return TRUE;
2967}
2968
2969static BOOLEAN vboxVddmPointerShapeToAttributes(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVBOXWDDM_POINTER_INFO pPointerInfo,
2970 bool fDwordAlignScanlines)
2971{
2972 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = &pPointerInfo->Attributes.data;
2973 /* pPointerAttributes maintains the visibility state, clear all except visibility */
2974 pPointerAttributes->Enable &= VBOX_MOUSE_POINTER_VISIBLE;
2975
2976 Assert(pSetPointerShape->Flags.Value == 1 || pSetPointerShape->Flags.Value == 2);
2977 if (pSetPointerShape->Flags.Color)
2978 {
2979 if (vboxWddmPointerCopyColorData(pSetPointerShape, pPointerAttributes, fDwordAlignScanlines))
2980 {
2981 pPointerAttributes->Flags = VIDEO_MODE_COLOR_POINTER;
2982 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_ALPHA;
2983 }
2984 else
2985 {
2986 LOGREL(("vboxWddmPointerCopyColorData failed"));
2987 AssertBreakpoint();
2988 return FALSE;
2989 }
2990
2991 }
2992 else if (pSetPointerShape->Flags.Monochrome)
2993 {
2994 if (vboxWddmPointerCopyMonoData(pSetPointerShape, pPointerAttributes, fDwordAlignScanlines))
2995 {
2996 pPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER;
2997 }
2998 else
2999 {
3000 LOGREL(("vboxWddmPointerCopyMonoData failed"));
3001 AssertBreakpoint();
3002 return FALSE;
3003 }
3004 }
3005 else
3006 {
3007 LOGREL(("unsupported pointer type Flags.Value(0x%x)", pSetPointerShape->Flags.Value));
3008 AssertBreakpoint();
3009 return FALSE;
3010 }
3011
3012 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_SHAPE;
3013
3014 /*
3015 * The hot spot coordinates and alpha flag will be encoded in the pPointerAttributes::Enable field.
3016 * High word will contain hot spot info and low word - flags.
3017 */
3018 pPointerAttributes->Enable |= (pSetPointerShape->YHot & 0xFF) << 24;
3019 pPointerAttributes->Enable |= (pSetPointerShape->XHot & 0xFF) << 16;
3020
3021 return TRUE;
3022}
3023
3024bool vboxWddmUpdatePointerShape(PVBOXMP_DEVEXT pDevExt, PVIDEO_POINTER_ATTRIBUTES pAttrs, uint32_t cbLength)
3025{
3026#ifdef VBOX_WITH_VMSVGA
3027 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VBOX)
3028 {
3029 NTSTATUS Status = STATUS_SUCCESS;
3030
3031 /** @todo Get rid of the unnecesary en-/decode procedure (XPDM legacy). */
3032 uint32_t fFlags = pAttrs->Enable & 0x0000FFFF;
3033 uint32_t xHot = (pAttrs->Enable >> 16) & 0xFF;
3034 uint32_t yHot = (pAttrs->Enable >> 24) & 0xFF;
3035 uint32_t cWidth = pAttrs->Width;
3036 uint32_t cHeight = pAttrs->Height;
3037 uint32_t cbAndMask = 0;
3038 uint32_t cbXorMask = 0;
3039
3040 if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
3041 {
3042 /* Size of the pointer data: sizeof(AND mask) + sizeof(XOR mask) */
3043 /* "Each scanline is padded to a 32-bit boundary." */
3044 cbAndMask = ((((cWidth + 7) / 8) + 3) & ~3) * cHeight;
3045 cbXorMask = cWidth * 4 * cHeight;
3046
3047 /* Send the shape to the host. */
3048 if (fFlags & VBOX_MOUSE_POINTER_ALPHA)
3049 {
3050 void const *pvImage = &pAttrs->Pixels[cbAndMask];
3051 Status = GaDefineAlphaCursor(pDevExt->pGa,
3052 xHot,
3053 yHot,
3054 cWidth,
3055 cHeight,
3056 pvImage,
3057 cbXorMask);
3058 }
3059 else
3060 {
3061 uint32_t u32AndMaskDepth = 1;
3062 uint32_t u32XorMaskDepth = 32;
3063
3064 void const *pvAndMask = &pAttrs->Pixels[0];
3065 void const *pvXorMask = &pAttrs->Pixels[cbAndMask];
3066 Status = GaDefineCursor(pDevExt->pGa,
3067 xHot,
3068 yHot,
3069 cWidth,
3070 cHeight,
3071 u32AndMaskDepth,
3072 u32XorMaskDepth,
3073 pvAndMask,
3074 cbAndMask,
3075 pvXorMask,
3076 cbXorMask);
3077 }
3078 }
3079
3080 /** @todo Hack: Use the legacy interface to handle visibility.
3081 * Eventually the VMSVGA WDDM driver should use the SVGA_FIFO_CURSOR_* interface.
3082 */
3083 VIDEO_POINTER_ATTRIBUTES attrs;
3084 RT_ZERO(attrs);
3085 attrs.Enable = pAttrs->Enable & VBOX_MOUSE_POINTER_VISIBLE;
3086 if (!VBoxMPCmnUpdatePointerShape(VBoxCommonFromDeviceExt(pDevExt), &attrs, sizeof(attrs)))
3087 {
3088 Status = STATUS_INVALID_PARAMETER;
3089 }
3090
3091 return Status == STATUS_SUCCESS;
3092 }
3093#endif
3094
3095 /* VBOXVIDEO_HWTYPE_VBOX */
3096 return VBoxMPCmnUpdatePointerShape(VBoxCommonFromDeviceExt(pDevExt), pAttrs, cbLength);
3097}
3098
3099static void vboxWddmHostPointerEnable(PVBOXMP_DEVEXT pDevExt, BOOLEAN fEnable)
3100{
3101 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
3102 RT_ZERO(PointerAttributes);
3103 if (fEnable)
3104 {
3105 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
3106 }
3107 vboxWddmUpdatePointerShape(pDevExt, &PointerAttributes, sizeof(PointerAttributes));
3108}
3109
3110NTSTATUS
3111APIENTRY
3112DxgkDdiSetPointerPosition(
3113 CONST HANDLE hAdapter,
3114 CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
3115{
3116// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3117
3118 vboxVDbgBreakFv();
3119
3120 /* mouse integration is ON */
3121 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3122 PVBOXWDDM_POINTER_INFO pPointerInfo = &pDevExt->aSources[pSetPointerPosition->VidPnSourceId].PointerInfo;
3123 PVBOXWDDM_GLOBAL_POINTER_INFO pGlobalPointerInfo = &pDevExt->PointerInfo;
3124 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = &pPointerInfo->Attributes.data;
3125 BOOLEAN fScreenVisState = !!(pPointerAttributes->Enable & VBOX_MOUSE_POINTER_VISIBLE);
3126 BOOLEAN fVisStateChanged = FALSE;
3127 BOOLEAN fScreenChanged = pGlobalPointerInfo->iLastReportedScreen != pSetPointerPosition->VidPnSourceId;
3128
3129 if (pSetPointerPosition->Flags.Visible)
3130 {
3131 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_VISIBLE;
3132 if (!fScreenVisState)
3133 {
3134 fVisStateChanged = TRUE;
3135 }
3136 }
3137 else
3138 {
3139 pPointerAttributes->Enable &= ~VBOX_MOUSE_POINTER_VISIBLE;
3140 if (fScreenVisState)
3141 {
3142 fVisStateChanged = TRUE;
3143 }
3144 }
3145
3146 pGlobalPointerInfo->iLastReportedScreen = pSetPointerPosition->VidPnSourceId;
3147
3148 if ((fVisStateChanged || fScreenChanged) && VBoxQueryHostWantsAbsolute())
3149 {
3150 if (fScreenChanged)
3151 {
3152 BOOLEAN bResult = vboxWddmUpdatePointerShape(pDevExt, &pPointerInfo->Attributes.data, VBOXWDDM_POINTER_ATTRIBUTES_SIZE);
3153 if (!bResult)
3154 {
3155 vboxWddmHostPointerEnable(pDevExt, FALSE);
3156 }
3157 }
3158
3159 // Always update the visibility as requested. Tell the host to use the guest's pointer.
3160 vboxWddmHostPointerEnable(pDevExt, pSetPointerPosition->Flags.Visible);
3161 }
3162
3163// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3164
3165 return STATUS_SUCCESS;
3166}
3167
3168NTSTATUS
3169APIENTRY
3170DxgkDdiSetPointerShape(
3171 CONST HANDLE hAdapter,
3172 CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
3173{
3174// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3175
3176 vboxVDbgBreakFv();
3177
3178 NTSTATUS Status = STATUS_NOT_SUPPORTED;
3179
3180 if (VBoxQueryHostWantsAbsolute())
3181 {
3182 /* mouse integration is ON */
3183 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3184 PVBOXWDDM_POINTER_INFO pPointerInfo = &pDevExt->aSources[pSetPointerShape->VidPnSourceId].PointerInfo;
3185 bool const fDwordAlignScanlines = pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VBOX;
3186 /** @todo to avoid extra data copy and extra heap allocation,
3187 * need to maintain the pre-allocated HGSMI buffer and convert the data directly to it */
3188 if (vboxVddmPointerShapeToAttributes(pSetPointerShape, pPointerInfo, fDwordAlignScanlines))
3189 {
3190 pDevExt->PointerInfo.iLastReportedScreen = pSetPointerShape->VidPnSourceId;
3191 if (vboxWddmUpdatePointerShape(pDevExt, &pPointerInfo->Attributes.data, VBOXWDDM_POINTER_ATTRIBUTES_SIZE))
3192 Status = STATUS_SUCCESS;
3193 else
3194 {
3195 // tell the host to use the guest's pointer
3196 vboxWddmHostPointerEnable(pDevExt, FALSE);
3197 }
3198 }
3199 }
3200
3201// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3202
3203 return Status;
3204}
3205
3206NTSTATUS
3207APIENTRY CALLBACK
3208DxgkDdiResetFromTimeout(
3209 CONST HANDLE hAdapter)
3210{
3211 RT_NOREF(hAdapter);
3212 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3213
3214 AssertBreakpoint();
3215 /** @todo fixme: implement */
3216
3217 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3218
3219 return STATUS_SUCCESS;
3220}
3221
3222
3223/* the lpRgnData->Buffer comes to us as RECT
3224 * to avoid extra memcpy we cast it to PRTRECT assuming
3225 * they are identical */
3226AssertCompile(sizeof(RECT) == sizeof(RTRECT));
3227AssertCompile(RT_OFFSETOF(RECT, left) == RT_OFFSETOF(RTRECT, xLeft));
3228AssertCompile(RT_OFFSETOF(RECT, bottom) == RT_OFFSETOF(RTRECT, yBottom));
3229AssertCompile(RT_OFFSETOF(RECT, right) == RT_OFFSETOF(RTRECT, xRight));
3230AssertCompile(RT_OFFSETOF(RECT, top) == RT_OFFSETOF(RTRECT, yTop));
3231
3232NTSTATUS
3233APIENTRY
3234DxgkDdiEscape(
3235 CONST HANDLE hAdapter,
3236 CONST DXGKARG_ESCAPE* pEscape)
3237{
3238 PAGED_CODE();
3239
3240// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3241
3242 NTSTATUS Status = STATUS_NOT_SUPPORTED;
3243 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3244 Assert(pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE));
3245 if (pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE))
3246 {
3247 PVBOXDISPIFESCAPE pEscapeHdr = (PVBOXDISPIFESCAPE)pEscape->pPrivateDriverData;
3248 switch (pEscapeHdr->escapeCode)
3249 {
3250 case VBOXESC_SETVISIBLEREGION:
3251 {
3252#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3253 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3254 if (!pContext)
3255 {
3256 WARN(("VBOXESC_SETVISIBLEREGION no context supplied!"));
3257 Status = STATUS_INVALID_PARAMETER;
3258 break;
3259 }
3260
3261 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS)
3262 {
3263 WARN(("VBOXESC_SETVISIBLEREGION invalid context supplied %d!", pContext->enmType));
3264 Status = STATUS_INVALID_PARAMETER;
3265 break;
3266 }
3267#endif
3268 /* visible regions for seamless */
3269 LPRGNDATA lpRgnData = VBOXDISPIFESCAPE_DATA(pEscapeHdr, RGNDATA);
3270 uint32_t cbData = VBOXDISPIFESCAPE_DATA_SIZE(pEscape->PrivateDriverDataSize);
3271 uint32_t cbRects = cbData - RT_UOFFSETOF(RGNDATA, Buffer);
3272 /* the lpRgnData->Buffer comes to us as RECT
3273 * to avoid extra memcpy we cast it to PRTRECT assuming
3274 * they are identical
3275 * see AssertCompile's above */
3276
3277 RTRECT *pRect = (RTRECT *)&lpRgnData->Buffer;
3278
3279 uint32_t cRects = cbRects/sizeof(RTRECT);
3280 int rc;
3281
3282 LOG(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRects=%d", cRects));
3283 Assert(cbRects >= sizeof(RTRECT)
3284 && cbRects == cRects*sizeof(RTRECT)
3285 && cRects == lpRgnData->rdh.nCount);
3286 if ( cbRects >= sizeof(RTRECT)
3287 && cbRects == cRects*sizeof(RTRECT)
3288 && cRects == lpRgnData->rdh.nCount)
3289 {
3290 /*
3291 * Inform the host about the visible region
3292 */
3293 VMMDevVideoSetVisibleRegion *pReq = NULL;
3294
3295 rc = VbglR0GRAlloc ((VMMDevRequestHeader **)&pReq,
3296 sizeof (VMMDevVideoSetVisibleRegion) + (cRects-1)*sizeof(RTRECT),
3297 VMMDevReq_VideoSetVisibleRegion);
3298 AssertRC(rc);
3299 if (RT_SUCCESS(rc))
3300 {
3301 pReq->cRect = cRects;
3302 memcpy(&pReq->Rect, pRect, cRects*sizeof(RTRECT));
3303
3304 rc = VbglR0GRPerform (&pReq->header);
3305 AssertRC(rc);
3306 if (RT_SUCCESS(rc))
3307 Status = STATUS_SUCCESS;
3308 else
3309 {
3310 WARN(("VbglR0GRPerform failed rc (%d)", rc));
3311 Status = STATUS_UNSUCCESSFUL;
3312 }
3313 VbglR0GRFree(&pReq->header);
3314 }
3315 else
3316 {
3317 WARN(("VbglR0GRAlloc failed rc (%d)", rc));
3318 Status = STATUS_UNSUCCESSFUL;
3319 }
3320 }
3321 else
3322 {
3323 WARN(("VBOXESC_SETVISIBLEREGION: incorrect buffer size (%d), reported count (%d)", cbRects, lpRgnData->rdh.nCount));
3324 Status = STATUS_INVALID_PARAMETER;
3325 }
3326 break;
3327 }
3328 case VBOXESC_ISVRDPACTIVE:
3329 /** @todo implement */
3330 Status = STATUS_SUCCESS;
3331 break;
3332 case VBOXESC_CONFIGURETARGETS:
3333 {
3334 LOG(("=> VBOXESC_CONFIGURETARGETS"));
3335
3336 if (!pEscape->Flags.HardwareAccess)
3337 {
3338 WARN(("VBOXESC_CONFIGURETARGETS called without HardwareAccess flag set, failing"));
3339 Status = STATUS_INVALID_PARAMETER;
3340 break;
3341 }
3342
3343#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3344 /* win8.1 does not allow context-based escapes for display-only mode */
3345 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3346 if (!pContext)
3347 {
3348 WARN(("VBOXESC_CONFIGURETARGETS no context supplied!"));
3349 Status = STATUS_INVALID_PARAMETER;
3350 break;
3351 }
3352
3353 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE)
3354 {
3355 WARN(("VBOXESC_CONFIGURETARGETS invalid context supplied %d!", pContext->enmType));
3356 Status = STATUS_INVALID_PARAMETER;
3357 break;
3358 }
3359#endif
3360
3361 if (pEscape->PrivateDriverDataSize != sizeof (*pEscapeHdr))
3362 {
3363 WARN(("VBOXESC_CONFIGURETARGETS invalid private driver size %d", pEscape->PrivateDriverDataSize));
3364 Status = STATUS_INVALID_PARAMETER;
3365 break;
3366 }
3367
3368 if (pEscapeHdr->u32CmdSpecific)
3369 {
3370 WARN(("VBOXESC_CONFIGURETARGETS invalid command %d", pEscapeHdr->u32CmdSpecific));
3371 Status = STATUS_INVALID_PARAMETER;
3372 break;
3373 }
3374
3375 HANDLE hKey = NULL;
3376 uint32_t cAdjusted = 0;
3377
3378 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3379 {
3380 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
3381 if (pTarget->fConfigured)
3382 continue;
3383
3384 pTarget->fConfigured = true;
3385
3386 if (!pTarget->fConnected)
3387 {
3388 Status = VBoxWddmChildStatusConnect(pDevExt, (uint32_t)i, TRUE);
3389 if (NT_SUCCESS(Status))
3390 ++cAdjusted;
3391 else
3392 WARN(("VBOXESC_CONFIGURETARGETS vboxWddmChildStatusConnectSecondaries failed Status 0x%x\n", Status));
3393 }
3394
3395 if (!hKey)
3396 {
3397 Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE, &hKey);
3398 if (!NT_SUCCESS(Status))
3399 {
3400 WARN(("VBOXESC_CONFIGURETARGETS IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
3401 hKey = NULL;
3402 continue;
3403 }
3404 }
3405
3406 Assert(hKey);
3407
3408 WCHAR wszNameBuf[sizeof(VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX) / sizeof(WCHAR) + 32];
3409 RTUtf16Printf(wszNameBuf, RT_ELEMENTS(wszNameBuf), "%ls%d", VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX, i);
3410 Status = vboxWddmRegSetValueDword(hKey, wszNameBuf, VBOXWDDM_CFG_DRVTARGET_CONNECTED);
3411 if (!NT_SUCCESS(Status))
3412 WARN(("VBOXESC_CONFIGURETARGETS vboxWddmRegSetValueDword (%ls) failed Status 0x%x\n", wszNameBuf, Status));
3413
3414 }
3415
3416 if (hKey)
3417 {
3418 NTSTATUS rcNt2 = ZwClose(hKey);
3419 Assert(rcNt2 == STATUS_SUCCESS); NOREF(rcNt2);
3420 }
3421
3422 pEscapeHdr->u32CmdSpecific = cAdjusted;
3423
3424 Status = STATUS_SUCCESS;
3425
3426 LOG(("<= VBOXESC_CONFIGURETARGETS"));
3427 break;
3428 }
3429 case VBOXESC_SETALLOCHOSTID:
3430 {
3431 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)pEscape->hDevice;
3432 if (!pDevice)
3433 {
3434 WARN(("VBOXESC_SETALLOCHOSTID called without no device specified, failing"));
3435 Status = STATUS_INVALID_PARAMETER;
3436 break;
3437 }
3438
3439 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_SETALLOCHOSTID))
3440 {
3441 WARN(("invalid buffer size for VBOXDISPIFESCAPE_SETALLOCHOSTID, was(%d), but expected (%d)",
3442 pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE_SETALLOCHOSTID)));
3443 Status = STATUS_INVALID_PARAMETER;
3444 break;
3445 }
3446
3447 if (!pEscape->Flags.HardwareAccess)
3448 {
3449 WARN(("VBOXESC_SETALLOCHOSTID not HardwareAccess"));
3450 Status = STATUS_INVALID_PARAMETER;
3451 break;
3452 }
3453
3454 PVBOXDISPIFESCAPE_SETALLOCHOSTID pSetHostID = (PVBOXDISPIFESCAPE_SETALLOCHOSTID)pEscapeHdr;
3455 PVBOXWDDM_ALLOCATION pAlloc = vboxWddmGetAllocationFromHandle(pDevExt, (D3DKMT_HANDLE)pSetHostID->hAlloc);
3456 if (!pAlloc)
3457 {
3458 WARN(("failed to get allocation from handle"));
3459 Status = STATUS_INVALID_PARAMETER;
3460 break;
3461 }
3462
3463 if (pAlloc->enmType != VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE)
3464 {
3465 WARN(("setHostID: invalid allocation type: %d", pAlloc->enmType));
3466 Status = STATUS_INVALID_PARAMETER;
3467 break;
3468 }
3469
3470 pSetHostID->rc = VBoxWddmOaSetHostID(pDevice, pAlloc, pSetHostID->hostID, &pSetHostID->EscapeHdr.u32CmdSpecific);
3471
3472 if (pAlloc->bAssigned)
3473 {
3474 PVBOXMP_DEVEXT pDevExt2 = pDevice->pAdapter;
3475 Assert(pAlloc->AllocData.SurfDesc.VidPnSourceId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt2)->cDisplays);
3476 PVBOXWDDM_SOURCE pSource = &pDevExt2->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
3477 if (pSource->AllocData.hostID != pAlloc->AllocData.hostID)
3478 {
3479 pSource->AllocData.hostID = pAlloc->AllocData.hostID;
3480 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
3481
3482 vboxWddmGhDisplayCheckSetInfo(pDevExt2);
3483 }
3484 }
3485
3486 Status = STATUS_SUCCESS;
3487 break;
3488 }
3489 case VBOXESC_ISANYX:
3490 {
3491 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_ISANYX))
3492 {
3493 WARN(("invalid private driver size %d", pEscape->PrivateDriverDataSize));
3494 Status = STATUS_INVALID_PARAMETER;
3495 break;
3496 }
3497
3498 PVBOXDISPIFESCAPE_ISANYX pIsAnyX = (PVBOXDISPIFESCAPE_ISANYX)pEscapeHdr;
3499 pIsAnyX->u32IsAnyX = VBoxCommonFromDeviceExt(pDevExt)->fAnyX;
3500 Status = STATUS_SUCCESS;
3501 break;
3502 }
3503 case VBOXESC_UPDATEMODES:
3504 {
3505 LOG(("=> VBOXESC_UPDATEMODES"));
3506
3507 if (!pEscape->Flags.HardwareAccess)
3508 {
3509 WARN(("VBOXESC_UPDATEMODES called without HardwareAccess flag set, failing"));
3510 Status = STATUS_INVALID_PARAMETER;
3511 break;
3512 }
3513
3514#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3515 /* win8.1 does not allow context-based escapes for display-only mode */
3516 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3517 if (!pContext)
3518 {
3519 WARN(("VBOXESC_UPDATEMODES no context supplied!"));
3520 Status = STATUS_INVALID_PARAMETER;
3521 break;
3522 }
3523
3524 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE)
3525 {
3526 WARN(("VBOXESC_UPDATEMODES invalid context supplied %d!", pContext->enmType));
3527 Status = STATUS_INVALID_PARAMETER;
3528 break;
3529 }
3530#endif
3531
3532 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_UPDATEMODES))
3533 {
3534 WARN(("VBOXESC_UPDATEMODES invalid private driver size %d", pEscape->PrivateDriverDataSize));
3535 Status = STATUS_INVALID_PARAMETER;
3536 break;
3537 }
3538
3539 VBOXDISPIFESCAPE_UPDATEMODES *pData = (VBOXDISPIFESCAPE_UPDATEMODES*)pEscapeHdr;
3540 Status = VBoxVidPnUpdateModes(pDevExt, pData->u32TargetId, &pData->Size);
3541 if (!NT_SUCCESS(Status))
3542 {
3543 WARN(("VBoxVidPnUpdateModes failed Status(%#x)\n", Status));
3544 return Status;
3545 }
3546
3547 Status = STATUS_SUCCESS;
3548 break;
3549 }
3550 case VBOXESC_TARGET_CONNECTIVITY:
3551 {
3552 if (!pEscape->Flags.HardwareAccess)
3553 {
3554 WARN(("VBOXESC_TARGET_CONNECTIVITY called without HardwareAccess flag set, failing"));
3555 Status = STATUS_INVALID_PARAMETER;
3556 break;
3557 }
3558
3559 if (pEscape->PrivateDriverDataSize != sizeof(VBOXDISPIFESCAPE_TARGETCONNECTIVITY))
3560 {
3561 WARN(("VBOXESC_TARGET_CONNECTIVITY invalid private driver size %d", pEscape->PrivateDriverDataSize));
3562 Status = STATUS_INVALID_PARAMETER;
3563 break;
3564 }
3565
3566 VBOXDISPIFESCAPE_TARGETCONNECTIVITY *pData = (VBOXDISPIFESCAPE_TARGETCONNECTIVITY *)pEscapeHdr;
3567 LOG(("=> VBOXESC_TARGET_CONNECTIVITY[%d] 0x%08X", pData->u32TargetId, pData->fu32Connect));
3568
3569 if (pData->u32TargetId >= (uint32_t)VBoxCommonFromDeviceExt(pDevExt)->cDisplays)
3570 {
3571 WARN(("VBOXESC_TARGET_CONNECTIVITY invalid screen index 0x%x", pData->u32TargetId));
3572 Status = STATUS_INVALID_PARAMETER;
3573 break;
3574 }
3575
3576 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[pData->u32TargetId];
3577 pTarget->fDisabled = !RT_BOOL(pData->fu32Connect & 1);
3578 pTarget->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_TOPOLOGY;
3579
3580 Status = STATUS_SUCCESS;
3581 break;
3582 }
3583 case VBOXESC_DBGPRINT:
3584 {
3585 /* use RT_OFFSETOF instead of sizeof since sizeof will give an aligned size that might
3586 * be bigger than the VBOXDISPIFESCAPE_DBGPRINT with a data containing just a few chars */
3587 Assert(pEscape->PrivateDriverDataSize >= RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]));
3588 /* only do DbgPrint when pEscape->PrivateDriverDataSize > RT_OFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1])
3589 * since == RT_OFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]) means the buffer contains just \0,
3590 * i.e. no need to print it */
3591 if (pEscape->PrivateDriverDataSize > RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]))
3592 {
3593 PVBOXDISPIFESCAPE_DBGPRINT pDbgPrint = (PVBOXDISPIFESCAPE_DBGPRINT)pEscapeHdr;
3594 /* ensure the last char is \0*/
3595 if (*((uint8_t*)pDbgPrint + pEscape->PrivateDriverDataSize - 1) == '\0')
3596 {
3597 if (g_VBoxLogUm & VBOXWDDM_CFG_LOG_UM_DBGPRINT)
3598 DbgPrint("%s\n", pDbgPrint->aStringBuf);
3599 if (g_VBoxLogUm & VBOXWDDM_CFG_LOG_UM_BACKDOOR)
3600 LOGREL_EXACT(("%s\n", pDbgPrint->aStringBuf));
3601 }
3602 }
3603 Status = STATUS_SUCCESS;
3604 break;
3605 }
3606 case VBOXESC_DBGDUMPBUF:
3607 {
3608 Status = vboxUmdDumpBuf((PVBOXDISPIFESCAPE_DBGDUMPBUF)pEscapeHdr, pEscape->PrivateDriverDataSize);
3609 break;
3610 }
3611 case VBOXESC_GUEST_DISPLAYCHANGED:
3612 {
3613 LOG(("=> VBOXESC_GUEST_DISPLAYCHANGED"));
3614
3615 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3616 {
3617#ifdef VBOX_WITH_VMSVGA
3618 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3619 {
3620 GaVidPnSourceCheckPos(pDevExt, i);
3621 continue;
3622 }
3623#endif
3624
3625 vboxWddmDisplaySettingsCheckPos(pDevExt, i);
3626 }
3627 Status = STATUS_SUCCESS;
3628 break;
3629 }
3630 default:
3631#ifdef VBOX_WITH_VMSVGA
3632 Status = GaDxgkDdiEscape(hAdapter, pEscape);
3633 if (NT_SUCCESS(Status) || Status != STATUS_NOT_SUPPORTED)
3634 break;
3635#endif
3636 WARN(("unsupported escape code (0x%x)", pEscapeHdr->escapeCode));
3637 break;
3638 }
3639 }
3640 else
3641 {
3642 WARN(("pEscape->PrivateDriverDataSize(%d) < (%d)", pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE)));
3643 Status = STATUS_BUFFER_TOO_SMALL;
3644 }
3645
3646// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3647
3648 return Status;
3649}
3650
3651NTSTATUS
3652APIENTRY
3653DxgkDdiCollectDbgInfo(
3654 CONST HANDLE hAdapter,
3655 CONST DXGKARG_COLLECTDBGINFO* pCollectDbgInfo
3656 )
3657{
3658 RT_NOREF(hAdapter, pCollectDbgInfo);
3659 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3660
3661 AssertBreakpoint();
3662
3663 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3664
3665 return STATUS_SUCCESS;
3666}
3667
3668NTSTATUS
3669APIENTRY
3670DxgkDdiIsSupportedVidPn(
3671 CONST HANDLE hAdapter,
3672 OUT DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPnArg
3673 )
3674{
3675 /* The DxgkDdiIsSupportedVidPn should be made pageable. */
3676 PAGED_CODE();
3677
3678 LOGF(("ENTER, context(0x%x)", hAdapter));
3679
3680 vboxVDbgBreakFv();
3681
3682 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3683 NTSTATUS Status = VBoxVidPnIsSupported(pDevExt, pIsSupportedVidPnArg->hDesiredVidPn, &pIsSupportedVidPnArg->IsVidPnSupported);
3684 if (!NT_SUCCESS(Status))
3685 {
3686 WARN(("VBoxVidPnIsSupported failed Status(%#x)\n", Status));
3687 return Status;
3688 }
3689
3690 LOGF(("LEAVE, isSupported(%d), context(0x%x)", pIsSupportedVidPnArg->IsVidPnSupported, hAdapter));
3691
3692 return STATUS_SUCCESS;
3693}
3694
3695NTSTATUS
3696APIENTRY
3697DxgkDdiRecommendFunctionalVidPn(
3698 CONST HANDLE hAdapter,
3699 CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPnArg
3700 )
3701{
3702 /* The DxgkDdiRecommendFunctionalVidPn should be made pageable. */
3703 PAGED_CODE();
3704
3705 LOGF(("ENTER, context(0x%x)", hAdapter));
3706
3707 vboxVDbgBreakFv();
3708
3709 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3710
3711 if (pRecommendFunctionalVidPnArg->PrivateDriverDataSize != sizeof (VBOXWDDM_RECOMMENDVIDPN))
3712 {
3713 WARN(("invalid size"));
3714 return STATUS_INVALID_PARAMETER;
3715 }
3716
3717 VBOXWDDM_RECOMMENDVIDPN *pData = (VBOXWDDM_RECOMMENDVIDPN*)pRecommendFunctionalVidPnArg->pPrivateDriverData;
3718 Assert(pData);
3719
3720 NTSTATUS Status = VBoxVidPnRecommendFunctional(pDevExt, pRecommendFunctionalVidPnArg->hRecommendedFunctionalVidPn, pData);
3721 if (!NT_SUCCESS(Status))
3722 {
3723 WARN(("VBoxVidPnRecommendFunctional failed %#x", Status));
3724 return Status;
3725 }
3726
3727 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3728
3729 return STATUS_SUCCESS;
3730}
3731
3732NTSTATUS
3733APIENTRY
3734DxgkDdiEnumVidPnCofuncModality(
3735 CONST HANDLE hAdapter,
3736 CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModalityArg
3737 )
3738{
3739 /* The DxgkDdiEnumVidPnCofuncModality function should be made pageable. */
3740 PAGED_CODE();
3741
3742 LOGF(("ENTER, context(0x%x)", hAdapter));
3743
3744 vboxVDbgBreakFv();
3745
3746 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3747
3748 NTSTATUS Status = VBoxVidPnCofuncModality(pDevExt, pEnumCofuncModalityArg->hConstrainingVidPn, pEnumCofuncModalityArg->EnumPivotType, &pEnumCofuncModalityArg->EnumPivot);
3749 if (!NT_SUCCESS(Status))
3750 {
3751 WARN(("VBoxVidPnCofuncModality failed Status(%#x)\n", Status));
3752 return Status;
3753 }
3754
3755 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3756
3757 return STATUS_SUCCESS;
3758}
3759
3760NTSTATUS
3761APIENTRY
3762DxgkDdiSetVidPnSourceAddress(
3763 CONST HANDLE hAdapter,
3764 CONST DXGKARG_SETVIDPNSOURCEADDRESS* pSetVidPnSourceAddress
3765 )
3766{
3767 /* The DxgkDdiSetVidPnSourceAddress function should be made pageable. */
3768 PAGED_CODE();
3769
3770 vboxVDbgBreakFv();
3771
3772 LOGF(("ENTER, context(0x%x)", hAdapter));
3773 LOG(("id %d, seg %d, addr 0x%RX64, hAllocation %p, ctx cnt %d, f 0x%x",
3774 pSetVidPnSourceAddress->VidPnSourceId,
3775 pSetVidPnSourceAddress->PrimarySegment,
3776 pSetVidPnSourceAddress->PrimaryAddress.QuadPart,
3777 pSetVidPnSourceAddress->hAllocation,
3778 pSetVidPnSourceAddress->ContextCount,
3779 pSetVidPnSourceAddress->Flags.Value));
3780
3781 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3782 if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceAddress->VidPnSourceId)
3783 {
3784 WARN(("invalid VidPnSourceId (%d), for displays(%d)", pSetVidPnSourceAddress->VidPnSourceId, VBoxCommonFromDeviceExt(pDevExt)->cDisplays));
3785 return STATUS_INVALID_PARAMETER;
3786 }
3787
3788#ifdef VBOX_WITH_VMSVGA
3789 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VMSVGA)
3790#endif
3791 vboxWddmDisplaySettingsCheckPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId);
3792
3793 NTSTATUS Status = STATUS_SUCCESS;
3794 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceAddress->VidPnSourceId];
3795
3796 /*
3797 * Update the source VRAM address.
3798 */
3799 PVBOXWDDM_ALLOCATION pAllocation;
3800 Assert(pSetVidPnSourceAddress->hAllocation);
3801 Assert(pSetVidPnSourceAddress->hAllocation || pSource->pPrimaryAllocation);
3802 Assert (pSetVidPnSourceAddress->Flags.Value < 2); /* i.e. 0 or 1 (ModeChange) */
3803
3804 if (pSetVidPnSourceAddress->hAllocation)
3805 {
3806 pAllocation = (PVBOXWDDM_ALLOCATION)pSetVidPnSourceAddress->hAllocation;
3807 vboxWddmAssignPrimary(pSource, pAllocation, pSetVidPnSourceAddress->VidPnSourceId);
3808 }
3809 else
3810 pAllocation = pSource->pPrimaryAllocation;
3811
3812 if (pAllocation)
3813 {
3814 vboxWddmAddrSetVram(&pAllocation->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment, (VBOXVIDEOOFFSET)pSetVidPnSourceAddress->PrimaryAddress.QuadPart);
3815 }
3816
3817 if (g_VBoxDisplayOnly && !pAllocation)
3818 {
3819 /* the VRAM here is an absolute address, nto an offset!
3820 * convert to offset since all internal VBox functionality is offset-based */
3821 vboxWddmAddrSetVram(&pSource->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment,
3822 vboxWddmVramAddrToOffset(pDevExt, pSetVidPnSourceAddress->PrimaryAddress));
3823 }
3824 else
3825 {
3826 Assert(!g_VBoxDisplayOnly);
3827 vboxWddmAddrSetVram(&pSource->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment,
3828 pSetVidPnSourceAddress->PrimaryAddress.QuadPart);
3829 }
3830
3831 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
3832
3833 /*
3834 * Report the source.
3835 */
3836#ifdef VBOX_WITH_VMSVGA
3837 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3838 {
3839 /* Query the position of the screen to make sure it is up to date. */
3840 vboxWddmDisplaySettingsQueryPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId, &pSource->VScreenPos);
3841
3842 GaVidPnSourceReport(pDevExt, pSource);
3843 return STATUS_SUCCESS;
3844 }
3845#endif
3846
3847 vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
3848
3849 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3850
3851 return Status;
3852}
3853
3854NTSTATUS
3855APIENTRY
3856DxgkDdiSetVidPnSourceVisibility(
3857 CONST HANDLE hAdapter,
3858 CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility
3859 )
3860{
3861 /* DxgkDdiSetVidPnSourceVisibility should be made pageable. */
3862 PAGED_CODE();
3863
3864 vboxVDbgBreakFv();
3865
3866 LOGF(("ENTER, context(0x%x)", hAdapter));
3867
3868 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3869
3870 if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceVisibility->VidPnSourceId)
3871 {
3872 WARN(("invalid VidPnSourceId (%d), for displays(%d)", pSetVidPnSourceVisibility->VidPnSourceId, VBoxCommonFromDeviceExt(pDevExt)->cDisplays));
3873 return STATUS_INVALID_PARAMETER;
3874 }
3875
3876#ifdef VBOX_WITH_VMSVGA
3877 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VMSVGA)
3878#endif
3879 vboxWddmDisplaySettingsCheckPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId);
3880
3881 NTSTATUS Status = STATUS_SUCCESS;
3882 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceVisibility->VidPnSourceId];
3883 PVBOXWDDM_ALLOCATION pAllocation = pSource->pPrimaryAllocation;
3884 if (pAllocation)
3885 {
3886 Assert(pAllocation->bVisible == pSource->bVisible);
3887 pAllocation->bVisible = pSetVidPnSourceVisibility->Visible;
3888 }
3889
3890 if (pSource->bVisible != pSetVidPnSourceVisibility->Visible)
3891 {
3892 pSource->bVisible = pSetVidPnSourceVisibility->Visible;
3893// pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_VISIBILITY;
3894// if (pDevExt->fCmdVbvaEnabled || pSource->bVisible)
3895// {
3896// vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
3897// }
3898 }
3899
3900#ifdef VBOX_WITH_VMSVGA
3901 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3902 {
3903 GaVidPnSourceCheckPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId);
3904 }
3905#endif
3906
3907 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3908
3909 return Status;
3910}
3911
3912NTSTATUS
3913APIENTRY
3914DxgkDdiCommitVidPn(
3915 CONST HANDLE hAdapter,
3916 CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPnArg
3917 )
3918{
3919 LOG(("ENTER AffectedVidPnSourceId(%d) hAdapter(0x%x)", pCommitVidPnArg->AffectedVidPnSourceId, hAdapter));
3920
3921 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3922 NTSTATUS Status;
3923
3924 vboxVDbgBreakFv();
3925
3926 VBOXWDDM_SOURCE *paSources = (VBOXWDDM_SOURCE*)RTMemAlloc(sizeof (VBOXWDDM_SOURCE) * VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3927 if (!paSources)
3928 {
3929 WARN(("RTMemAlloc failed"));
3930 return STATUS_NO_MEMORY;
3931 }
3932
3933 VBOXWDDM_TARGET *paTargets = (VBOXWDDM_TARGET*)RTMemAlloc(sizeof (VBOXWDDM_TARGET) * VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3934 if (!paTargets)
3935 {
3936 WARN(("RTMemAlloc failed"));
3937 RTMemFree(paSources);
3938 return STATUS_NO_MEMORY;
3939 }
3940
3941 VBoxVidPnSourcesInit(paSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, VBOXWDDM_HGSYNC_F_SYNCED_ALL);
3942
3943 VBoxVidPnTargetsInit(paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, VBOXWDDM_HGSYNC_F_SYNCED_ALL);
3944
3945 VBoxVidPnSourcesCopy(paSources, pDevExt->aSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3946 VBoxVidPnTargetsCopy(paTargets, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3947
3948 do {
3949 const DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
3950 Status = pDevExt->u.primary.DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPnArg->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
3951 if (!NT_SUCCESS(Status))
3952 {
3953 WARN(("DxgkCbQueryVidPnInterface failed Status 0x%x", Status));
3954 break;
3955 }
3956
3957#ifdef VBOXWDDM_DEBUG_VIDPN
3958 vboxVidPnDumpVidPn("\n>>>>COMMIT VidPN: >>>>", pDevExt, pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface, "<<<<<<<<<<<<<<<<<<<<\n");
3959#endif
3960
3961 if (pCommitVidPnArg->AffectedVidPnSourceId != D3DDDI_ID_ALL)
3962 {
3963 Status = VBoxVidPnCommitSourceModeForSrcId(
3964 pDevExt,
3965 pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface,
3966 (PVBOXWDDM_ALLOCATION)pCommitVidPnArg->hPrimaryAllocation,
3967 pCommitVidPnArg->AffectedVidPnSourceId, paSources, paTargets, pCommitVidPnArg->Flags.PathPowerTransition);
3968 if (!NT_SUCCESS(Status))
3969 {
3970 WARN(("VBoxVidPnCommitSourceModeForSrcId for current VidPn failed Status 0x%x", Status));
3971 break;
3972 }
3973 }
3974 else
3975 {
3976 Status = VBoxVidPnCommitAll(pDevExt, pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface,
3977 (PVBOXWDDM_ALLOCATION)pCommitVidPnArg->hPrimaryAllocation,
3978 paSources, paTargets);
3979 if (!NT_SUCCESS(Status))
3980 {
3981 WARN(("VBoxVidPnCommitAll for current VidPn failed Status 0x%x", Status));
3982 break;
3983 }
3984 }
3985
3986 Assert(NT_SUCCESS(Status));
3987 pDevExt->u.primary.hCommittedVidPn = pCommitVidPnArg->hFunctionalVidPn;
3988 VBoxVidPnSourcesCopy(pDevExt->aSources, paSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3989 VBoxVidPnTargetsCopy(pDevExt->aTargets, paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3990
3991 VBoxDumpSourceTargetArrays(paSources, paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3992
3993#ifdef VBOX_WITH_VMSVGA
3994 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3995 {
3996 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3997 {
3998 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[i];
3999
4000 LOG(("Source [%d]: visible %d, blanked %d", i, pSource->bVisible, pSource->bBlankedByPowerOff));
4001
4002 /* Update positions of all screens. */
4003 vboxWddmDisplaySettingsQueryPos(pDevExt, i, &pSource->VScreenPos);
4004
4005 GaVidPnSourceReport(pDevExt, pSource);
4006 }
4007
4008 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
4009 {
4010 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
4011 Assert(pTarget->u32Id == (unsigned)i);
4012 if (pTarget->VidPnSourceId != D3DDDI_ID_UNINITIALIZED)
4013 {
4014 continue;
4015 }
4016
4017 LOG(("Target [%d]: blanked %d", i, pTarget->fBlankedByPowerOff));
4018
4019 if (pTarget->fBlankedByPowerOff)
4020 {
4021 GaScreenDefine(pDevExt->pGa, 0, pTarget->u32Id, 0, 0, 0, 0, true);
4022 }
4023 else
4024 {
4025 GaScreenDestroy(pDevExt->pGa, pTarget->u32Id);
4026 }
4027 }
4028
4029 break;
4030 }
4031#endif
4032 vboxWddmGhDisplayCheckSetInfo(pDevExt);
4033 } while (0);
4034
4035 RTMemFree(paSources);
4036 RTMemFree(paTargets);
4037
4038 LOG(("LEAVE, status(0x%x), hAdapter(0x%x)", Status, hAdapter));
4039
4040 return Status;
4041}
4042
4043NTSTATUS
4044APIENTRY
4045DxgkDdiUpdateActiveVidPnPresentPath(
4046 CONST HANDLE hAdapter,
4047 CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPathArg
4048 )
4049{
4050 RT_NOREF(hAdapter, pUpdateActiveVidPnPresentPathArg);
4051 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4052
4053 AssertBreakpoint();
4054
4055 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4056
4057 return STATUS_SUCCESS;
4058}
4059
4060NTSTATUS
4061APIENTRY
4062DxgkDdiRecommendMonitorModes(
4063 CONST HANDLE hAdapter,
4064 CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModesArg
4065 )
4066{
4067 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4068
4069 vboxVDbgBreakFv();
4070
4071 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4072
4073 NTSTATUS Status = VBoxVidPnRecommendMonitorModes(pDevExt, pRecommendMonitorModesArg->VideoPresentTargetId,
4074 pRecommendMonitorModesArg->hMonitorSourceModeSet, pRecommendMonitorModesArg->pMonitorSourceModeSetInterface);
4075 if (!NT_SUCCESS(Status))
4076 {
4077 WARN(("VBoxVidPnRecommendMonitorModes failed %#x", Status));
4078 return Status;
4079 }
4080
4081 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4082
4083 return STATUS_SUCCESS;
4084}
4085
4086NTSTATUS
4087APIENTRY
4088DxgkDdiRecommendVidPnTopology(
4089 CONST HANDLE hAdapter,
4090 CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopologyArg
4091 )
4092{
4093 RT_NOREF(hAdapter, pRecommendVidPnTopologyArg);
4094 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4095
4096 vboxVDbgBreakFv();
4097
4098 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4099
4100 return STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY;
4101}
4102
4103NTSTATUS
4104APIENTRY
4105DxgkDdiGetScanLine(
4106 CONST HANDLE hAdapter,
4107 DXGKARG_GETSCANLINE* pGetScanLine)
4108{
4109 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4110
4111 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4112
4113#ifdef DEBUG_misha
4114// RT_BREAKPOINT();
4115#endif
4116
4117 NTSTATUS Status = VBoxWddmSlGetScanLine(pDevExt, pGetScanLine);
4118
4119 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4120
4121 return Status;
4122}
4123
4124NTSTATUS
4125APIENTRY
4126DxgkDdiStopCapture(
4127 CONST HANDLE hAdapter,
4128 CONST DXGKARG_STOPCAPTURE* pStopCapture)
4129{
4130 RT_NOREF(hAdapter, pStopCapture);
4131 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4132
4133 AssertBreakpoint();
4134
4135 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4136
4137 return STATUS_SUCCESS;
4138}
4139
4140NTSTATUS
4141APIENTRY
4142DxgkDdiControlInterrupt(
4143 CONST HANDLE hAdapter,
4144 CONST DXGK_INTERRUPT_TYPE InterruptType,
4145 BOOLEAN Enable
4146 )
4147{
4148 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4149
4150 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
4151 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4152
4153 switch (InterruptType)
4154 {
4155 case DXGK_INTERRUPT_DISPLAYONLY_VSYNC:
4156 case DXGK_INTERRUPT_CRTC_VSYNC:
4157 {
4158 Status = VBoxWddmSlEnableVSyncNotification(pDevExt, Enable);
4159 if (NT_SUCCESS(Status))
4160 Status = STATUS_SUCCESS; /* <- sanity */
4161 else
4162 WARN(("VSYNC Interrupt control failed Enable(%d), Status(0x%x)", Enable, Status));
4163 break;
4164 }
4165 case DXGK_INTERRUPT_DMA_COMPLETED:
4166 case DXGK_INTERRUPT_DMA_PREEMPTED:
4167 case DXGK_INTERRUPT_DMA_FAULTED:
4168 WARN(("Unexpected interrupt type! %d", InterruptType));
4169 break;
4170 default:
4171 WARN(("UNSUPPORTED interrupt type! %d", InterruptType));
4172 break;
4173 }
4174
4175 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4176
4177 return Status;
4178}
4179
4180NTSTATUS
4181APIENTRY
4182DxgkDdiCreateOverlay(
4183 CONST HANDLE hAdapter,
4184 DXGKARG_CREATEOVERLAY *pCreateOverlay)
4185{
4186 LOGF(("ENTER, hAdapter(0x%p)", hAdapter));
4187
4188 NTSTATUS Status = STATUS_SUCCESS;
4189
4190#ifdef VBOX_WITH_VIDEOHWACCEL
4191 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4192 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)vboxWddmMemAllocZero(sizeof (VBOXWDDM_OVERLAY));
4193 Assert(pOverlay);
4194 if (pOverlay)
4195 {
4196 int rc = vboxVhwaHlpOverlayCreate(pDevExt, pCreateOverlay->VidPnSourceId, &pCreateOverlay->OverlayInfo, pOverlay);
4197 AssertRC(rc);
4198 if (RT_SUCCESS(rc))
4199 {
4200 pCreateOverlay->hOverlay = pOverlay;
4201 }
4202 else
4203 {
4204 vboxWddmMemFree(pOverlay);
4205 Status = STATUS_UNSUCCESSFUL;
4206 }
4207 }
4208 else
4209 Status = STATUS_NO_MEMORY;
4210#else
4211 RT_NOREF(hAdapter, pCreateOverlay);
4212#endif
4213
4214 LOGF(("LEAVE, hAdapter(0x%p)", hAdapter));
4215
4216 return Status;
4217}
4218
4219NTSTATUS
4220APIENTRY
4221DxgkDdiDestroyDevice(
4222 CONST HANDLE hDevice)
4223{
4224 /* DxgkDdiDestroyDevice should be made pageable. */
4225 PAGED_CODE();
4226
4227 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4228
4229 vboxVDbgBreakFv();
4230
4231#ifdef VBOX_WITH_VMSVGA
4232 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4233 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4234 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4235 {
4236 GaDeviceDestroy(pDevExt->pGa, pDevice);
4237 }
4238#endif
4239
4240 vboxWddmMemFree(hDevice);
4241
4242 LOGF(("LEAVE, "));
4243
4244 return STATUS_SUCCESS;
4245}
4246
4247
4248
4249/*
4250 * DxgkDdiOpenAllocation
4251 */
4252NTSTATUS
4253APIENTRY
4254DxgkDdiOpenAllocation(
4255 CONST HANDLE hDevice,
4256 CONST DXGKARG_OPENALLOCATION *pOpenAllocation)
4257{
4258 /* DxgkDdiOpenAllocation should be made pageable. */
4259 PAGED_CODE();
4260
4261 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4262
4263 vboxVDbgBreakFv();
4264
4265 NTSTATUS Status = STATUS_SUCCESS;
4266 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4267 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4268 PVBOXWDDM_RCINFO pRcInfo = NULL;
4269 if (pOpenAllocation->PrivateDriverSize)
4270 {
4271 Assert(pOpenAllocation->pPrivateDriverData);
4272 if (pOpenAllocation->PrivateDriverSize == sizeof (VBOXWDDM_RCINFO))
4273 {
4274 pRcInfo = (PVBOXWDDM_RCINFO)pOpenAllocation->pPrivateDriverData;
4275 Assert(pRcInfo->cAllocInfos == pOpenAllocation->NumAllocations);
4276 }
4277 else
4278 {
4279 WARN(("Invalid PrivateDriverSize %d", pOpenAllocation->PrivateDriverSize));
4280 Status = STATUS_INVALID_PARAMETER;
4281 }
4282 }
4283
4284 if (Status == STATUS_SUCCESS)
4285 {
4286 UINT i = 0;
4287 for (; i < pOpenAllocation->NumAllocations; ++i)
4288 {
4289 DXGK_OPENALLOCATIONINFO* pInfo = &pOpenAllocation->pOpenAllocation[i];
4290#ifdef VBOX_WITH_VMSVGA3D_DX
4291 Assert( pInfo->PrivateDriverDataSize == sizeof(VBOXDXALLOCATIONDESC)
4292 || pInfo->PrivateDriverDataSize == sizeof(VBOXWDDM_ALLOCINFO));
4293#else
4294 Assert(pInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_ALLOCINFO));
4295#endif
4296 Assert(pInfo->pPrivateDriverData);
4297 PVBOXWDDM_ALLOCATION pAllocation = vboxWddmGetAllocationFromHandle(pDevExt, pInfo->hAllocation);
4298 if (!pAllocation)
4299 {
4300 WARN(("invalid handle"));
4301 Status = STATUS_INVALID_PARAMETER;
4302 break;
4303 }
4304
4305#ifdef DEBUG
4306 Assert(!pAllocation->fAssumedDeletion);
4307#endif
4308 if (pRcInfo)
4309 {
4310 Assert(pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC);
4311
4312 if (pInfo->PrivateDriverDataSize != sizeof (VBOXWDDM_ALLOCINFO)
4313 || !pInfo->pPrivateDriverData)
4314 {
4315 WARN(("invalid data size"));
4316 Status = STATUS_INVALID_PARAMETER;
4317 break;
4318 }
4319
4320#ifdef VBOX_WITH_VIDEOHWACCEL
4321 PVBOXWDDM_ALLOCINFO pAllocInfo = (PVBOXWDDM_ALLOCINFO)pInfo->pPrivateDriverData;
4322
4323 if (pRcInfo->RcDesc.fFlags.Overlay)
4324 {
4325 /* we have queried host for some surface info, like pitch & size,
4326 * need to return it back to the UMD (User Mode Drive) */
4327 pAllocInfo->SurfDesc = pAllocation->AllocData.SurfDesc;
4328 /* success, just continue */
4329 }
4330#endif
4331 }
4332
4333 KIRQL OldIrql;
4334 PVBOXWDDM_OPENALLOCATION pOa;
4335 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
4336 pOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
4337 if (pOa)
4338 {
4339 ++pOa->cOpens;
4340 ++pAllocation->cOpens;
4341 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4342 }
4343 else
4344 {
4345 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4346 pOa = (PVBOXWDDM_OPENALLOCATION)vboxWddmMemAllocZero(sizeof (VBOXWDDM_OPENALLOCATION));
4347 if (!pOa)
4348 {
4349 WARN(("failed to allocation alloc info"));
4350 Status = STATUS_INSUFFICIENT_RESOURCES;
4351 break;
4352 }
4353
4354 pOa->hAllocation = pInfo->hAllocation;
4355 pOa->pAllocation = pAllocation;
4356 pOa->pDevice = pDevice;
4357 pOa->cOpens = 1;
4358
4359 PVBOXWDDM_OPENALLOCATION pConcurrentOa;
4360 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
4361 pConcurrentOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
4362 if (!pConcurrentOa)
4363 InsertHeadList(&pAllocation->OpenList, &pOa->ListEntry);
4364 else
4365 ++pConcurrentOa->cOpens;
4366 ++pAllocation->cOpens;
4367 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4368 if (pConcurrentOa)
4369 {
4370 vboxWddmMemFree(pOa);
4371 pOa = pConcurrentOa;
4372 }
4373 }
4374
4375 pInfo->hDeviceSpecificAllocation = pOa;
4376 }
4377
4378 if (Status != STATUS_SUCCESS)
4379 {
4380 for (UINT j = 0; j < i; ++j)
4381 {
4382 DXGK_OPENALLOCATIONINFO* pInfo2Free = &pOpenAllocation->pOpenAllocation[j];
4383 PVBOXWDDM_OPENALLOCATION pOa2Free = (PVBOXWDDM_OPENALLOCATION)pInfo2Free->hDeviceSpecificAllocation;
4384 VBoxWddmOaRelease(pOa2Free);
4385 }
4386 }
4387 }
4388 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4389
4390 return Status;
4391}
4392
4393NTSTATUS
4394APIENTRY
4395DxgkDdiCloseAllocation(
4396 CONST HANDLE hDevice,
4397 CONST DXGKARG_CLOSEALLOCATION* pCloseAllocation)
4398{
4399 RT_NOREF(hDevice);
4400 /* DxgkDdiCloseAllocation should be made pageable. */
4401 PAGED_CODE();
4402
4403 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4404
4405 vboxVDbgBreakFv();
4406
4407 for (UINT i = 0; i < pCloseAllocation->NumAllocations; ++i)
4408 {
4409 PVBOXWDDM_OPENALLOCATION pOa2Free = (PVBOXWDDM_OPENALLOCATION)pCloseAllocation->pOpenHandleList[i];
4410 PVBOXWDDM_ALLOCATION pAllocation = pOa2Free->pAllocation;
4411 Assert(pAllocation->cShRcRefs >= pOa2Free->cShRcRefs);
4412 pAllocation->cShRcRefs -= pOa2Free->cShRcRefs;
4413 VBoxWddmOaRelease(pOa2Free);
4414 }
4415
4416 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4417
4418 return STATUS_SUCCESS;
4419}
4420
4421#define VBOXVDMACMD_DMA_PRESENT_BLT_MINSIZE() (VBOXVDMACMD_SIZE(VBOXVDMACMD_DMA_PRESENT_BLT))
4422#define VBOXVDMACMD_DMA_PRESENT_BLT_SIZE(_c) (VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[_c]))
4423
4424DECLINLINE(BOOLEAN) vboxWddmPixFormatConversionSupported(D3DDDIFORMAT From, D3DDDIFORMAT To)
4425{
4426 Assert(From != D3DDDIFMT_UNKNOWN);
4427 Assert(To != D3DDDIFMT_UNKNOWN);
4428 Assert(From == To);
4429 return From == To;
4430}
4431
4432NTSTATUS
4433APIENTRY
4434DxgkDdiUpdateOverlay(
4435 CONST HANDLE hOverlay,
4436 CONST DXGKARG_UPDATEOVERLAY *pUpdateOverlay)
4437{
4438 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4439
4440 NTSTATUS Status = STATUS_SUCCESS;
4441
4442#ifdef VBOX_WITH_VIDEOHWACCEL
4443 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4444 AssertPtr(pOverlay);
4445 int rc = vboxVhwaHlpOverlayUpdate(pOverlay, &pUpdateOverlay->OverlayInfo);
4446 AssertRC(rc);
4447 if (RT_FAILURE(rc))
4448 Status = STATUS_UNSUCCESSFUL;
4449#else
4450 RT_NOREF(hOverlay, pUpdateOverlay);
4451#endif
4452
4453 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4454 return Status;
4455}
4456
4457NTSTATUS
4458APIENTRY
4459DxgkDdiFlipOverlay(
4460 CONST HANDLE hOverlay,
4461 CONST DXGKARG_FLIPOVERLAY *pFlipOverlay)
4462{
4463 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4464
4465 NTSTATUS Status = STATUS_SUCCESS;
4466
4467#ifdef VBOX_WITH_VIDEOHWACCEL
4468 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4469 AssertPtr(pOverlay);
4470 int rc = vboxVhwaHlpOverlayFlip(pOverlay, pFlipOverlay);
4471 AssertRC(rc);
4472 if (RT_FAILURE(rc))
4473 Status = STATUS_UNSUCCESSFUL;
4474#else
4475 RT_NOREF(hOverlay, pFlipOverlay);
4476#endif
4477
4478 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4479
4480 return Status;
4481}
4482
4483NTSTATUS
4484APIENTRY
4485DxgkDdiDestroyOverlay(
4486 CONST HANDLE hOverlay)
4487{
4488 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4489
4490 NTSTATUS Status = STATUS_SUCCESS;
4491
4492#ifdef VBOX_WITH_VIDEOHWACCEL
4493 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4494 AssertPtr(pOverlay);
4495 int rc = vboxVhwaHlpOverlayDestroy(pOverlay);
4496 AssertRC(rc);
4497 if (RT_SUCCESS(rc))
4498 vboxWddmMemFree(pOverlay);
4499 else
4500 Status = STATUS_UNSUCCESSFUL;
4501#else
4502 RT_NOREF(hOverlay);
4503#endif
4504
4505 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4506
4507 return Status;
4508}
4509
4510/**
4511 * DxgkDdiCreateContext
4512 */
4513NTSTATUS
4514APIENTRY
4515DxgkDdiCreateContext(
4516 CONST HANDLE hDevice,
4517 DXGKARG_CREATECONTEXT *pCreateContext)
4518{
4519 /* DxgkDdiCreateContext should be made pageable */
4520 PAGED_CODE();
4521
4522 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4523
4524 vboxVDbgBreakFv();
4525
4526 if (pCreateContext->NodeOrdinal >= VBOXWDDM_NUM_NODES)
4527 {
4528 WARN(("Invalid NodeOrdinal (%d), expected to be less that (%d)\n", pCreateContext->NodeOrdinal, VBOXWDDM_NUM_NODES));
4529 return STATUS_INVALID_PARAMETER;
4530 }
4531
4532 NTSTATUS Status = STATUS_SUCCESS;
4533 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4534 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4535 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)vboxWddmMemAllocZero(sizeof (VBOXWDDM_CONTEXT));
4536 Assert(pContext);
4537 if (pContext)
4538 {
4539 pContext->pDevice = pDevice;
4540 pContext->hContext = pCreateContext->hContext;
4541 pContext->EngineAffinity = pCreateContext->EngineAffinity;
4542 pContext->NodeOrdinal = pCreateContext->NodeOrdinal;
4543 vboxVideoCmCtxInitEmpty(&pContext->CmContext);
4544 if (pCreateContext->Flags.SystemContext || pCreateContext->PrivateDriverDataSize == 0)
4545 {
4546 Assert(pCreateContext->PrivateDriverDataSize == 0);
4547 Assert(!pCreateContext->pPrivateDriverData);
4548 Assert(pCreateContext->Flags.Value <= 2); /* 2 is a GDI context in Win7 */
4549 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_SYSTEM;
4550
4551 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VBOX)
4552 {
4553 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
4554 {
4555 vboxWddmDisplaySettingsCheckPos(pDevExt, i);
4556 }
4557 }
4558 Status = STATUS_SUCCESS;
4559 }
4560 else
4561 {
4562 Assert(pCreateContext->Flags.Value == 0);
4563 Assert(pCreateContext->PrivateDriverDataSize == sizeof (VBOXWDDM_CREATECONTEXT_INFO));
4564 Assert(pCreateContext->pPrivateDriverData);
4565 if (pCreateContext->PrivateDriverDataSize == sizeof (VBOXWDDM_CREATECONTEXT_INFO))
4566 {
4567 PVBOXWDDM_CREATECONTEXT_INFO pInfo = (PVBOXWDDM_CREATECONTEXT_INFO)pCreateContext->pPrivateDriverData;
4568 switch (pInfo->enmType)
4569 {
4570 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE:
4571 {
4572 pContext->enmType = pInfo->enmType;
4573 ASMAtomicIncU32(&pDevExt->cContextsDispIfResize);
4574 break;
4575 }
4576 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS:
4577 {
4578 pContext->enmType = pInfo->enmType;
4579 Status = vboxVideoCmCtxAdd(&pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext, (HANDLE)pInfo->u.vbox.hUmEvent, pInfo->u.vbox.u64UmInfo);
4580 if (!NT_SUCCESS(Status))
4581 {
4582 WARN(("vboxVideoCmCtxAdd failed, Status 0x%x", Status));
4583 }
4584 break;
4585 }
4586#ifdef VBOX_WITH_VMSVGA
4587 case VBOXWDDM_CONTEXT_TYPE_GA_3D:
4588 {
4589 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_GA_3D;
4590 Status = GaContextCreate(pDevExt->pGa, pInfo, pContext);
4591 break;
4592 }
4593#endif
4594#ifdef VBOX_WITH_VMSVGA3D_DX
4595 case VBOXWDDM_CONTEXT_TYPE_VMSVGA_D3D:
4596 {
4597 /* VMSVGA_D3D context type shares some code with GA_3D, because both work with VMSVGA GPU. */
4598 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_VMSVGA_D3D;
4599 Status = GaContextCreate(pDevExt->pGa, pInfo, pContext);
4600 break;
4601 }
4602#endif
4603 default:
4604 {
4605 WARN(("unsupported context type %d", pInfo->enmType));
4606 Status = STATUS_INVALID_PARAMETER;
4607 break;
4608 }
4609 }
4610 }
4611 }
4612
4613 if (Status == STATUS_SUCCESS)
4614 {
4615 pCreateContext->hContext = pContext;
4616 pCreateContext->ContextInfo.DmaBufferSize = VBOXWDDM_C_DMA_BUFFER_SIZE;
4617 pCreateContext->ContextInfo.DmaBufferSegmentSet = 0;
4618 pCreateContext->ContextInfo.DmaBufferPrivateDataSize = VBOXWDDM_C_DMA_PRIVATEDATA_SIZE;
4619 pCreateContext->ContextInfo.AllocationListSize = VBOXWDDM_C_ALLOC_LIST_SIZE;
4620 pCreateContext->ContextInfo.PatchLocationListSize = VBOXWDDM_C_PATH_LOCATION_LIST_SIZE;
4621 //#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN7)
4622 //# error port to Win7 DDI
4623 // //pCreateContext->ContextInfo.DmaBufferAllocationGroup = ???;
4624 //#endif // DXGKDDI_INTERFACE_VERSION
4625 }
4626 else
4627 vboxWddmMemFree(pContext);
4628 }
4629 else
4630 Status = STATUS_NO_MEMORY;
4631
4632 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4633
4634 return Status;
4635}
4636
4637NTSTATUS
4638APIENTRY
4639DxgkDdiDestroyContext(
4640 CONST HANDLE hContext)
4641{
4642 LOGF(("ENTER, hContext(0x%x)", hContext));
4643 vboxVDbgBreakFv();
4644 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
4645 PVBOXMP_DEVEXT pDevExt = pContext->pDevice->pAdapter;
4646 NTSTATUS Status = STATUS_SUCCESS;
4647
4648 switch(pContext->enmType)
4649 {
4650 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE:
4651 {
4652 uint32_t cContexts = ASMAtomicDecU32(&pDevExt->cContextsDispIfResize);
4653 Assert(cContexts < UINT32_MAX/2);
4654 if (!cContexts)
4655 {
4656 if (pDevExt->fDisableTargetUpdate)
4657 {
4658 pDevExt->fDisableTargetUpdate = FALSE;
4659 vboxWddmGhDisplayCheckSetInfoEx(pDevExt, true);
4660 }
4661 }
4662 break;
4663 }
4664 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS:
4665 {
4666 Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext);
4667 if (!NT_SUCCESS(Status))
4668 WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status));
4669
4670 Assert(pContext->CmContext.pSession == NULL);
4671 break;
4672 }
4673#ifdef VBOX_WITH_VMSVGA
4674 case VBOXWDDM_CONTEXT_TYPE_GA_3D:
4675 {
4676 Status = GaContextDestroy(pDevExt->pGa, pContext);
4677 break;
4678 }
4679#endif
4680#ifdef VBOX_WITH_VMSVGA3D_DX
4681 case VBOXWDDM_CONTEXT_TYPE_VMSVGA_D3D:
4682 {
4683 Status = GaContextDestroy(pDevExt->pGa, pContext);
4684 break;
4685 }
4686#endif
4687 default:
4688 break;
4689 }
4690
4691 Status = vboxVideoAMgrCtxDestroy(&pContext->AllocContext);
4692 if (NT_SUCCESS(Status))
4693 {
4694 Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->CmMgr, &pContext->CmContext);
4695 if (NT_SUCCESS(Status))
4696 vboxWddmMemFree(pContext);
4697 else
4698 WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status));
4699 }
4700 else
4701 WARN(("vboxVideoAMgrCtxDestroy failed, Status 0x%x", Status));
4702
4703 LOGF(("LEAVE, hContext(0x%x)", hContext));
4704
4705 return Status;
4706}
4707
4708NTSTATUS
4709APIENTRY
4710DxgkDdiLinkDevice(
4711 __in CONST PDEVICE_OBJECT PhysicalDeviceObject,
4712 __in CONST PVOID MiniportDeviceContext,
4713 __inout PLINKED_DEVICE LinkedDevice
4714 )
4715{
4716 RT_NOREF(PhysicalDeviceObject, MiniportDeviceContext, LinkedDevice);
4717 LOGF(("ENTER, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
4718 vboxVDbgBreakFv();
4719 AssertBreakpoint();
4720 LOGF(("LEAVE, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
4721 return STATUS_NOT_IMPLEMENTED;
4722}
4723
4724NTSTATUS
4725APIENTRY
4726DxgkDdiSetDisplayPrivateDriverFormat(
4727 CONST HANDLE hAdapter,
4728 /*CONST*/ DXGKARG_SETDISPLAYPRIVATEDRIVERFORMAT* pSetDisplayPrivateDriverFormat
4729 )
4730{
4731 RT_NOREF(hAdapter, pSetDisplayPrivateDriverFormat);
4732 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4733 vboxVDbgBreakFv();
4734 AssertBreakpoint();
4735 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4736 return STATUS_SUCCESS;
4737}
4738
4739NTSTATUS APIENTRY CALLBACK DxgkDdiRestartFromTimeout(IN_CONST_HANDLE hAdapter)
4740{
4741 RT_NOREF(hAdapter);
4742 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4743 vboxVDbgBreakFv();
4744 AssertBreakpoint();
4745 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4746 return STATUS_SUCCESS;
4747}
4748
4749static NTSTATUS APIENTRY DxgkDdiQueryVidPnHWCapability(
4750 __in const HANDLE hAdapter,
4751 __inout DXGKARG_QUERYVIDPNHWCAPABILITY *pVidPnHWCaps
4752 )
4753{
4754 RT_NOREF(hAdapter);
4755 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4756 vboxVDbgBreakF();
4757 pVidPnHWCaps->VidPnHWCaps.DriverRotation = 0;
4758 pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0;
4759 pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0;
4760 pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 0;
4761 pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0;
4762 pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0;
4763 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4764 return STATUS_SUCCESS;
4765}
4766
4767static NTSTATUS APIENTRY DxgkDdiPresentDisplayOnly(
4768 _In_ const HANDLE hAdapter,
4769 _In_ const DXGKARG_PRESENT_DISPLAYONLY *pPresentDisplayOnly
4770 )
4771{
4772 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4773 vboxVDbgBreakFv();
4774
4775 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4776#ifdef VBOX_WITH_VMSVGA
4777 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4778 {
4779 return GaDxgkDdiPresentDisplayOnly(hAdapter, pPresentDisplayOnly);
4780 }
4781#endif
4782 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pPresentDisplayOnly->VidPnSourceId];
4783 Assert(pSource->AllocData.Addr.SegmentId == 1);
4784 VBOXWDDM_ALLOC_DATA SrcAllocData;
4785 SrcAllocData.SurfDesc.width = pPresentDisplayOnly->Pitch * pPresentDisplayOnly->BytesPerPixel;
4786 SrcAllocData.SurfDesc.height = ~0UL;
4787 switch (pPresentDisplayOnly->BytesPerPixel)
4788 {
4789 case 4:
4790 SrcAllocData.SurfDesc.format = D3DDDIFMT_A8R8G8B8;
4791 break;
4792 case 3:
4793 SrcAllocData.SurfDesc.format = D3DDDIFMT_R8G8B8;
4794 break;
4795 case 2:
4796 SrcAllocData.SurfDesc.format = D3DDDIFMT_R5G6B5;
4797 break;
4798 case 1:
4799 SrcAllocData.SurfDesc.format = D3DDDIFMT_P8;
4800 break;
4801 default:
4802 WARN(("Unknown format"));
4803 SrcAllocData.SurfDesc.format = D3DDDIFMT_UNKNOWN;
4804 break;
4805 }
4806 SrcAllocData.SurfDesc.bpp = pPresentDisplayOnly->BytesPerPixel >> 3;
4807 SrcAllocData.SurfDesc.pitch = pPresentDisplayOnly->Pitch;
4808 SrcAllocData.SurfDesc.depth = 1;
4809 SrcAllocData.SurfDesc.slicePitch = pPresentDisplayOnly->Pitch;
4810 SrcAllocData.SurfDesc.cbSize = ~0UL;
4811 SrcAllocData.Addr.SegmentId = 0;
4812 SrcAllocData.Addr.pvMem = pPresentDisplayOnly->pSource;
4813 SrcAllocData.hostID = 0;
4814
4815 RECT UpdateRect;
4816 RT_ZERO(UpdateRect);
4817 BOOLEAN bUpdateRectInited = FALSE;
4818
4819 for (UINT i = 0; i < pPresentDisplayOnly->NumMoves; ++i)
4820 {
4821 if (!bUpdateRectInited)
4822 {
4823 UpdateRect = pPresentDisplayOnly->pMoves[i].DestRect;
4824 bUpdateRectInited = TRUE;
4825 }
4826 else
4827 vboxWddmRectUnite(&UpdateRect, &pPresentDisplayOnly->pMoves[i].DestRect);
4828 vboxVdmaGgDmaBltPerform(pDevExt, &SrcAllocData, &pPresentDisplayOnly->pMoves[i].DestRect, &pSource->AllocData, &pPresentDisplayOnly->pMoves[i].DestRect);
4829 }
4830
4831 for (UINT i = 0; i < pPresentDisplayOnly->NumDirtyRects; ++i)
4832 {
4833 RECT *pDirtyRect = &pPresentDisplayOnly->pDirtyRect[i];
4834
4835 if (pDirtyRect->left >= pDirtyRect->right || pDirtyRect->top >= pDirtyRect->bottom)
4836 {
4837 WARN(("Wrong dirty rect (%d, %d)-(%d, %d)",
4838 pDirtyRect->left, pDirtyRect->top, pDirtyRect->right, pDirtyRect->bottom));
4839 continue;
4840 }
4841
4842 vboxVdmaGgDmaBltPerform(pDevExt, &SrcAllocData, pDirtyRect, &pSource->AllocData, pDirtyRect);
4843
4844 if (!bUpdateRectInited)
4845 {
4846 UpdateRect = *pDirtyRect;
4847 bUpdateRectInited = TRUE;
4848 }
4849 else
4850 vboxWddmRectUnite(&UpdateRect, pDirtyRect);
4851 }
4852
4853 if (bUpdateRectInited && pSource->bVisible)
4854 {
4855 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UpdateRect);
4856 }
4857
4858 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4859 return STATUS_SUCCESS;
4860}
4861
4862static NTSTATUS DxgkDdiStopDeviceAndReleasePostDisplayOwnership(
4863 _In_ PVOID MiniportDeviceContext,
4864 _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
4865 _Out_ PDXGK_DISPLAY_INFORMATION DisplayInfo
4866)
4867{
4868 RT_NOREF(MiniportDeviceContext, TargetId, DisplayInfo);
4869 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4870 vboxVDbgBreakFv();
4871 AssertBreakpoint();
4872 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4873 return STATUS_NOT_SUPPORTED;
4874}
4875
4876static NTSTATUS DxgkDdiSystemDisplayEnable(
4877 _In_ PVOID MiniportDeviceContext,
4878 _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
4879 _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
4880 _Out_ UINT *Width,
4881 _Out_ UINT *Height,
4882 _Out_ D3DDDIFORMAT *ColorFormat
4883 )
4884{
4885 RT_NOREF(MiniportDeviceContext, TargetId, Flags, Width, Height, ColorFormat);
4886 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4887 vboxVDbgBreakFv();
4888 AssertBreakpoint();
4889 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4890 return STATUS_NOT_SUPPORTED;
4891}
4892
4893static VOID DxgkDdiSystemDisplayWrite(
4894 _In_ PVOID MiniportDeviceContext,
4895 _In_ PVOID Source,
4896 _In_ UINT SourceWidth,
4897 _In_ UINT SourceHeight,
4898 _In_ UINT SourceStride,
4899 _In_ UINT PositionX,
4900 _In_ UINT PositionY
4901)
4902{
4903 RT_NOREF(MiniportDeviceContext, Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY);
4904 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4905 vboxVDbgBreakFv();
4906 AssertBreakpoint();
4907 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4908}
4909
4910static NTSTATUS DxgkDdiGetChildContainerId(
4911 _In_ PVOID MiniportDeviceContext,
4912 _In_ ULONG ChildUid,
4913 _Inout_ PDXGK_CHILD_CONTAINER_ID ContainerId
4914)
4915{
4916 RT_NOREF(MiniportDeviceContext, ChildUid, ContainerId);
4917 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4918 vboxVDbgBreakFv();
4919 AssertBreakpoint();
4920 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4921 return STATUS_SUCCESS;
4922}
4923
4924static NTSTATUS APIENTRY DxgkDdiSetPowerComponentFState(
4925 _In_ const HANDLE DriverContext,
4926 UINT ComponentIndex,
4927 UINT FState
4928)
4929{
4930 RT_NOREF(DriverContext, ComponentIndex, FState);
4931 LOGF(("ENTER, DriverContext(0x%x)", DriverContext));
4932 vboxVDbgBreakFv();
4933 AssertBreakpoint();
4934 LOGF(("LEAVE, DriverContext(0x%x)", DriverContext));
4935 return STATUS_SUCCESS;
4936}
4937
4938static NTSTATUS APIENTRY DxgkDdiPowerRuntimeControlRequest(
4939 _In_ const HANDLE DriverContext,
4940 _In_ LPCGUID PowerControlCode,
4941 _In_opt_ PVOID InBuffer,
4942 _In_ SIZE_T InBufferSize,
4943 _Out_opt_ PVOID OutBuffer,
4944 _In_ SIZE_T OutBufferSize,
4945 _Out_opt_ PSIZE_T BytesReturned
4946)
4947{
4948 RT_NOREF(DriverContext, PowerControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned);
4949 LOGF(("ENTER, DriverContext(0x%x)", DriverContext));
4950 vboxVDbgBreakFv();
4951 AssertBreakpoint();
4952 LOGF(("LEAVE, DriverContext(0x%x)", DriverContext));
4953 return STATUS_SUCCESS;
4954}
4955
4956static NTSTATUS DxgkDdiNotifySurpriseRemoval(
4957 _In_ PVOID MiniportDeviceContext,
4958 _In_ DXGK_SURPRISE_REMOVAL_TYPE RemovalType
4959 )
4960{
4961 RT_NOREF(MiniportDeviceContext, RemovalType);
4962 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4963 vboxVDbgBreakFv();
4964 AssertBreakpoint();
4965 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4966 return STATUS_SUCCESS;
4967}
4968
4969static BOOLEAN DxgkDdiInterruptRoutine(const PVOID MiniportDeviceContext,
4970 ULONG MessageNumber)
4971{
4972#ifdef VBOX_WITH_VMSVGA
4973 BOOLEAN const fVMSVGA = GaDxgkDdiInterruptRoutine(MiniportDeviceContext, MessageNumber);
4974#else
4975 BOOLEAN const fVMSVGA = FALSE;
4976#endif
4977
4978 BOOLEAN const fHGSMI = DxgkDdiInterruptRoutineLegacy(MiniportDeviceContext, MessageNumber);
4979 return fVMSVGA || fHGSMI;
4980}
4981
4982static VOID DxgkDdiDpcRoutine(const PVOID MiniportDeviceContext)
4983{
4984 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
4985
4986#ifdef VBOX_WITH_VMSVGA
4987 GaDxgkDdiDpcRoutine(MiniportDeviceContext);
4988#endif
4989 DxgkDdiDpcRoutineLegacy(MiniportDeviceContext);
4990
4991 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
4992}
4993
4994static NTSTATUS vboxWddmInitDisplayOnlyDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
4995{
4996 KMDDOD_INITIALIZATION_DATA DriverInitializationData = {'\0'};
4997
4998 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_WIN8;
4999
5000 DriverInitializationData.DxgkDdiAddDevice = DxgkDdiAddDevice;
5001 DriverInitializationData.DxgkDdiStartDevice = DxgkDdiStartDevice;
5002 DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice;
5003 DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice;
5004 DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest;
5005 DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine;
5006 DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine;
5007 DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations;
5008 DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus;
5009 DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor;
5010 DriverInitializationData.DxgkDdiSetPowerState = DxgkDdiSetPowerState;
5011 DriverInitializationData.DxgkDdiNotifyAcpiEvent = DxgkDdiNotifyAcpiEvent;
5012 DriverInitializationData.DxgkDdiResetDevice = DxgkDdiResetDevice;
5013 DriverInitializationData.DxgkDdiUnload = DxgkDdiUnload;
5014 DriverInitializationData.DxgkDdiQueryInterface = DxgkDdiQueryInterface;
5015 DriverInitializationData.DxgkDdiControlEtwLogging = DxgkDdiControlEtwLogging;
5016 DriverInitializationData.DxgkDdiQueryAdapterInfo = DxgkDdiQueryAdapterInfo;
5017 DriverInitializationData.DxgkDdiSetPalette = DxgkDdiSetPalette;
5018 DriverInitializationData.DxgkDdiSetPointerPosition = DxgkDdiSetPointerPosition;
5019 DriverInitializationData.DxgkDdiSetPointerShape = DxgkDdiSetPointerShape;
5020 DriverInitializationData.DxgkDdiEscape = DxgkDdiEscape;
5021 DriverInitializationData.DxgkDdiCollectDbgInfo = DxgkDdiCollectDbgInfo;
5022 DriverInitializationData.DxgkDdiIsSupportedVidPn = DxgkDdiIsSupportedVidPn;
5023 DriverInitializationData.DxgkDdiRecommendFunctionalVidPn = DxgkDdiRecommendFunctionalVidPn;
5024 DriverInitializationData.DxgkDdiEnumVidPnCofuncModality = DxgkDdiEnumVidPnCofuncModality;
5025 DriverInitializationData.DxgkDdiSetVidPnSourceVisibility = DxgkDdiSetVidPnSourceVisibility;
5026 DriverInitializationData.DxgkDdiCommitVidPn = DxgkDdiCommitVidPn;
5027 DriverInitializationData.DxgkDdiUpdateActiveVidPnPresentPath = DxgkDdiUpdateActiveVidPnPresentPath;
5028 DriverInitializationData.DxgkDdiRecommendMonitorModes = DxgkDdiRecommendMonitorModes;
5029 DriverInitializationData.DxgkDdiQueryVidPnHWCapability = DxgkDdiQueryVidPnHWCapability;
5030 DriverInitializationData.DxgkDdiPresentDisplayOnly = DxgkDdiPresentDisplayOnly;
5031 DriverInitializationData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = DxgkDdiStopDeviceAndReleasePostDisplayOwnership;
5032 DriverInitializationData.DxgkDdiSystemDisplayEnable = DxgkDdiSystemDisplayEnable;
5033 DriverInitializationData.DxgkDdiSystemDisplayWrite = DxgkDdiSystemDisplayWrite;
5034// DriverInitializationData.DxgkDdiGetChildContainerId = DxgkDdiGetChildContainerId;
5035// DriverInitializationData.DxgkDdiSetPowerComponentFState = DxgkDdiSetPowerComponentFState;
5036// DriverInitializationData.DxgkDdiPowerRuntimeControlRequest = DxgkDdiPowerRuntimeControlRequest;
5037// DriverInitializationData.DxgkDdiNotifySurpriseRemoval = DxgkDdiNotifySurpriseRemoval;
5038
5039 /* Display-only driver is not required to report VSYNC.
5040 * The Microsoft KMDOD driver sample does not implement DxgkDdiControlInterrupt and DxgkDdiGetScanLine.
5041 * The functions must be either both implemented or none implemented.
5042 * Windows 10 10586 guests had problems with VSYNC in display-only driver (#8228).
5043 * Therefore the driver does not implement DxgkDdiControlInterrupt and DxgkDdiGetScanLine.
5044 */
5045
5046 NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject,
5047 pRegistryPath,
5048 &DriverInitializationData);
5049 if (!NT_SUCCESS(Status))
5050 {
5051 WARN(("DxgkInitializeDisplayOnlyDriver failed! Status 0x%x", Status));
5052 }
5053 return Status;
5054}
5055
5056static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath, VBOXVIDEO_HWTYPE enmHwType)
5057{
5058 DRIVER_INITIALIZATION_DATA DriverInitializationData = {'\0'};
5059
5060 // Fill in the DriverInitializationData structure and call DxgkInitialize()
5061 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
5062 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_WIN8;
5063 else
5064 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_VISTA_SP1;
5065
5066 DriverInitializationData.DxgkDdiAddDevice = DxgkDdiAddDevice;
5067 DriverInitializationData.DxgkDdiStartDevice = DxgkDdiStartDevice;
5068 DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice;
5069 DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice;
5070 DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest;
5071 DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine;
5072 DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine;
5073
5074#ifdef VBOX_WITH_VMSVGA
5075 if (enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
5076 {
5077 DriverInitializationData.DxgkDdiPatch = GaDxgkDdiPatch;
5078 DriverInitializationData.DxgkDdiSubmitCommand = GaDxgkDdiSubmitCommand;
5079 DriverInitializationData.DxgkDdiPreemptCommand = GaDxgkDdiPreemptCommand;
5080 DriverInitializationData.DxgkDdiBuildPagingBuffer = GaDxgkDdiBuildPagingBuffer;
5081 DriverInitializationData.DxgkDdiQueryCurrentFence = GaDxgkDdiQueryCurrentFence;
5082 DriverInitializationData.DxgkDdiRender = GaDxgkDdiRender;
5083 DriverInitializationData.DxgkDdiPresent = SvgaDxgkDdiPresent;
5084 }
5085 else
5086#endif
5087 {
5088 RT_NOREF(enmHwType);
5089
5090 DriverInitializationData.DxgkDdiPatch = DxgkDdiPatchLegacy;
5091 DriverInitializationData.DxgkDdiSubmitCommand = DxgkDdiSubmitCommandLegacy;
5092 DriverInitializationData.DxgkDdiPreemptCommand = DxgkDdiPreemptCommandLegacy;
5093 DriverInitializationData.DxgkDdiBuildPagingBuffer = DxgkDdiBuildPagingBufferLegacy;
5094 DriverInitializationData.DxgkDdiQueryCurrentFence = DxgkDdiQueryCurrentFenceLegacy;
5095 DriverInitializationData.DxgkDdiRender = DxgkDdiRenderLegacy;
5096 DriverInitializationData.DxgkDdiPresent = DxgkDdiPresentLegacy;
5097 }
5098
5099 DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations;
5100 DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus;
5101 DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor;
5102 DriverInitializationData.DxgkDdiSetPowerState = DxgkDdiSetPowerState;
5103 DriverInitializationData.DxgkDdiNotifyAcpiEvent = DxgkDdiNotifyAcpiEvent;
5104 DriverInitializationData.DxgkDdiResetDevice = DxgkDdiResetDevice;
5105 DriverInitializationData.DxgkDdiUnload = DxgkDdiUnload;
5106 DriverInitializationData.DxgkDdiQueryInterface = DxgkDdiQueryInterface;
5107 DriverInitializationData.DxgkDdiControlEtwLogging = DxgkDdiControlEtwLogging;
5108
5109 DriverInitializationData.DxgkDdiQueryAdapterInfo = DxgkDdiQueryAdapterInfo;
5110 DriverInitializationData.DxgkDdiCreateDevice = DxgkDdiCreateDevice;
5111 DriverInitializationData.DxgkDdiCreateAllocation = DxgkDdiCreateAllocation;
5112 DriverInitializationData.DxgkDdiDestroyAllocation = DxgkDdiDestroyAllocation;
5113 DriverInitializationData.DxgkDdiDescribeAllocation = DxgkDdiDescribeAllocation;
5114 DriverInitializationData.DxgkDdiGetStandardAllocationDriverData = DxgkDdiGetStandardAllocationDriverData;
5115 DriverInitializationData.DxgkDdiAcquireSwizzlingRange = DxgkDdiAcquireSwizzlingRange;
5116 DriverInitializationData.DxgkDdiReleaseSwizzlingRange = DxgkDdiReleaseSwizzlingRange;
5117
5118 DriverInitializationData.DxgkDdiSetPalette = DxgkDdiSetPalette;
5119 DriverInitializationData.DxgkDdiSetPointerPosition = DxgkDdiSetPointerPosition;
5120 DriverInitializationData.DxgkDdiSetPointerShape = DxgkDdiSetPointerShape;
5121 DriverInitializationData.DxgkDdiResetFromTimeout = DxgkDdiResetFromTimeout;
5122 DriverInitializationData.DxgkDdiRestartFromTimeout = DxgkDdiRestartFromTimeout;
5123 DriverInitializationData.DxgkDdiEscape = DxgkDdiEscape;
5124 DriverInitializationData.DxgkDdiCollectDbgInfo = DxgkDdiCollectDbgInfo;
5125 DriverInitializationData.DxgkDdiIsSupportedVidPn = DxgkDdiIsSupportedVidPn;
5126 DriverInitializationData.DxgkDdiRecommendFunctionalVidPn = DxgkDdiRecommendFunctionalVidPn;
5127 DriverInitializationData.DxgkDdiEnumVidPnCofuncModality = DxgkDdiEnumVidPnCofuncModality;
5128 DriverInitializationData.DxgkDdiSetVidPnSourceAddress = DxgkDdiSetVidPnSourceAddress;
5129 DriverInitializationData.DxgkDdiSetVidPnSourceVisibility = DxgkDdiSetVidPnSourceVisibility;
5130 DriverInitializationData.DxgkDdiCommitVidPn = DxgkDdiCommitVidPn;
5131 DriverInitializationData.DxgkDdiUpdateActiveVidPnPresentPath = DxgkDdiUpdateActiveVidPnPresentPath;
5132 DriverInitializationData.DxgkDdiRecommendMonitorModes = DxgkDdiRecommendMonitorModes;
5133 DriverInitializationData.DxgkDdiRecommendVidPnTopology = DxgkDdiRecommendVidPnTopology;
5134 DriverInitializationData.DxgkDdiGetScanLine = DxgkDdiGetScanLine;
5135 DriverInitializationData.DxgkDdiStopCapture = DxgkDdiStopCapture;
5136 DriverInitializationData.DxgkDdiControlInterrupt = DxgkDdiControlInterrupt;
5137 DriverInitializationData.DxgkDdiCreateOverlay = DxgkDdiCreateOverlay;
5138
5139 DriverInitializationData.DxgkDdiDestroyDevice = DxgkDdiDestroyDevice;
5140 DriverInitializationData.DxgkDdiOpenAllocation = DxgkDdiOpenAllocation;
5141 DriverInitializationData.DxgkDdiCloseAllocation = DxgkDdiCloseAllocation;
5142
5143 DriverInitializationData.DxgkDdiUpdateOverlay = DxgkDdiUpdateOverlay;
5144 DriverInitializationData.DxgkDdiFlipOverlay = DxgkDdiFlipOverlay;
5145 DriverInitializationData.DxgkDdiDestroyOverlay = DxgkDdiDestroyOverlay;
5146
5147 DriverInitializationData.DxgkDdiCreateContext = DxgkDdiCreateContext;
5148 DriverInitializationData.DxgkDdiDestroyContext = DxgkDdiDestroyContext;
5149
5150 DriverInitializationData.DxgkDdiLinkDevice = NULL; //DxgkDdiLinkDevice;
5151 DriverInitializationData.DxgkDdiSetDisplayPrivateDriverFormat = DxgkDdiSetDisplayPrivateDriverFormat;
5152
5153 if (DriverInitializationData.Version >= DXGKDDI_INTERFACE_VERSION_WIN7)
5154 {
5155 DriverInitializationData.DxgkDdiQueryVidPnHWCapability = DxgkDdiQueryVidPnHWCapability;
5156 }
5157
5158 NTSTATUS Status = DxgkInitialize(pDriverObject,
5159 pRegistryPath,
5160 &DriverInitializationData);
5161 if (!NT_SUCCESS(Status))
5162 {
5163 WARN(("DxgkInitialize failed! Status 0x%x", Status));
5164 }
5165 return Status;
5166}
5167
5168NTSTATUS
5169DriverEntry(
5170 IN PDRIVER_OBJECT DriverObject,
5171 IN PUNICODE_STRING RegistryPath
5172 )
5173{
5174 PAGED_CODE();
5175
5176 vboxVDbgBreakFv();
5177
5178 int irc = RTR0Init(0);
5179 if (RT_FAILURE(irc))
5180 {
5181 RTLogBackdoorPrintf("VBoxWddm: RTR0Init failed: %Rrc!\n", irc);
5182 return STATUS_UNSUCCESSFUL;
5183 }
5184
5185#if 0//def DEBUG_misha
5186 RTLogGroupSettings(0, "+default.e.l.f.l2.l3");
5187#endif
5188
5189#ifdef DEBUG
5190#define VBOXWDDM_BUILD_TYPE "dbg"
5191#else
5192#define VBOXWDDM_BUILD_TYPE "rel"
5193#endif
5194
5195 LOGREL(("VBox WDDM Driver for Windows %s version %d.%d.%dr%d %s, %d bit; Built %s %s",
5196 VBoxQueryWinVersion(NULL) >= WINVERSION_8 ? "8+" : "Vista and 7",
5197 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
5198 VBOXWDDM_BUILD_TYPE,
5199 (sizeof (void*) << 3), __DATE__, __TIME__));
5200
5201 if ( !ARGUMENT_PRESENT(DriverObject)
5202 || !ARGUMENT_PRESENT(RegistryPath))
5203 return STATUS_INVALID_PARAMETER;
5204
5205 vboxWddmDrvCfgInit(RegistryPath);
5206
5207 ULONG major, minor, build;
5208 BOOLEAN fCheckedBuild = PsGetVersion(&major, &minor, &build, NULL); NOREF(fCheckedBuild);
5209 BOOLEAN f3DRequired = FALSE;
5210
5211 LOGREL(("OsVersion(%d, %d, %d)", major, minor, build));
5212
5213 NTSTATUS Status = STATUS_SUCCESS;
5214 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
5215 int rc = VbglR0InitClient();
5216 if (RT_SUCCESS(rc))
5217 {
5218 /* Check whether 3D is required by the guest. */
5219 if (major > 6)
5220 {
5221 /* Windows 10 and newer. */
5222 f3DRequired = TRUE;
5223 }
5224 else if (major == 6)
5225 {
5226 if (minor >= 2)
5227 {
5228 /* Windows 8, 8.1 and 10 preview. */
5229 f3DRequired = TRUE;
5230 }
5231 else
5232 {
5233 f3DRequired = FALSE;
5234 }
5235 }
5236 else
5237 {
5238 WARN(("Unsupported OLDER win version, ignore and assume 3D is NOT required"));
5239 f3DRequired = FALSE;
5240 }
5241
5242 LOG(("3D is %srequired!", f3DRequired? "": "NOT "));
5243
5244 /* Check whether 3D is provided by the host. */
5245 VBOXVIDEO_HWTYPE enmHwType = VBOXVIDEO_HWTYPE_VBOX;
5246 BOOL f3DSupported = FALSE;
5247
5248 if (VBoxVGACfgAvailable())
5249 {
5250 /* New configuration query interface is available. */
5251 uint32_t u32;
5252 if (VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VERSION, &u32, 0))
5253 {
5254 LOGREL(("WDDM: VGA configuration version %d", u32));
5255 }
5256
5257 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_3D, &u32, 0);
5258 f3DSupported = RT_BOOL(u32);
5259
5260 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VMSVGA, &u32, 0);
5261 if (u32)
5262 {
5263 enmHwType = VBOXVIDEO_HWTYPE_VMSVGA;
5264 }
5265 LOGREL(("WDDM: VGA configuration: 3D %d, hardware type %d", f3DSupported, enmHwType));
5266 }
5267
5268 if (enmHwType == VBOXVIDEO_HWTYPE_VBOX)
5269 {
5270 /* No 3D for legacy adapter. */
5271 f3DSupported = FALSE;
5272 }
5273 else if (enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
5274 {
5275 /* Nothing. */
5276 }
5277 else
5278 {
5279 /* No supported hardware, fallback to VBox 2D only. */
5280 enmHwType = VBOXVIDEO_HWTYPE_VBOX;
5281 f3DSupported = FALSE;
5282 }
5283
5284 LOGREL(("WDDM: 3D is %ssupported, hardware type %d", f3DSupported? "": "not ", enmHwType));
5285
5286 if (NT_SUCCESS(Status))
5287 {
5288 if (!f3DSupported)
5289 {
5290 /* No 3D support by the host. */
5291 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
5292 {
5293 /* Use display only driver for Win8+. */
5294 g_VBoxDisplayOnly = 1;
5295
5296 /* Black list some builds. */
5297 if (major == 6 && minor == 4 && build == 9841)
5298 {
5299 /* W10 Technical preview crashes with display-only driver. */
5300 LOGREL(("3D is NOT supported by the host, fallback to the system video driver."));
5301 Status = STATUS_UNSUCCESSFUL;
5302 }
5303 else
5304 {
5305 LOGREL(("3D is NOT supported by the host, falling back to display-only mode.."));
5306 }
5307 }
5308 else
5309 {
5310 if (f3DRequired)
5311 {
5312 LOGREL(("3D is NOT supported by the host, but is required for the current guest version using this driver.."));
5313 Status = STATUS_UNSUCCESSFUL;
5314 }
5315 else
5316 LOGREL(("3D is NOT supported by the host, but is NOT required for the current guest version using this driver, continuing with Disabled 3D.."));
5317 }
5318 }
5319 }
5320
5321 if (NT_SUCCESS(Status))
5322 {
5323 if (g_VBoxDisplayOnly)
5324 {
5325 Status = vboxWddmInitDisplayOnlyDriver(DriverObject, RegistryPath);
5326 }
5327 else
5328 {
5329 Status = vboxWddmInitFullGraphicsDriver(DriverObject, RegistryPath, enmHwType);
5330 }
5331
5332 if (NT_SUCCESS(Status))
5333 {
5334 /*
5335 * Successfully initialized the driver.
5336 */
5337 return Status;
5338 }
5339
5340 /*
5341 * Cleanup on failure.
5342 */
5343 }
5344 else
5345 LOGREL(("Aborting the video driver load due to 3D support missing"));
5346
5347 VbglR0TerminateClient();
5348 }
5349 else
5350 {
5351 WARN(("VbglR0InitClient failed, rc(%d)", rc));
5352 Status = STATUS_UNSUCCESSFUL;
5353 }
5354
5355 AssertRelease(!NT_SUCCESS(Status));
5356
5357 PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
5358 if (pLogger)
5359 {
5360 RTLogDestroy(pLogger);
5361 }
5362 pLogger = RTLogSetDefaultInstance(NULL);
5363 if (pLogger)
5364 {
5365 RTLogDestroy(pLogger);
5366 }
5367
5368 return Status;
5369}
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