VirtualBox

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

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

WDDM: use VRAM segment for primary surfaces. bugref:9845

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 193.9 KB
Line 
1/* $Id: VBoxMPWddm.cpp 95290 2022-06-15 15:15:06Z 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 if (SvgaIsDXSupported(pDevExt))
2161 {
2162 pAllocationInfo->PreferredSegment.Value = 0;
2163 pAllocationInfo->SupportedReadSegmentSet = 1; /* VRAM */
2164 pAllocationInfo->SupportedWriteSegmentSet = 1; /* VRAM */
2165 /// @todo Required? pAllocationInfo->Flags.CpuVisible = 1;
2166 }
2167 break;
2168 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
2169#ifdef VBOX_WITH_VIDEOHWACCEL
2170 if (pAllocInfo->fFlags.Overlay)
2171 {
2172 /* actually we can not "properly" issue create overlay commands to the host here
2173 * because we do not know source VidPn id here, i.e.
2174 * the primary which is supposed to be overlayed,
2175 * however we need to get some info like pitch & size from the host here */
2176 int rc = vboxVhwaHlpGetSurfInfo(pDevExt, pAllocation);
2177 AssertRC(rc);
2178 if (RT_SUCCESS(rc))
2179 {
2180 pAllocationInfo->Flags.Overlay = 1;
2181 pAllocationInfo->Flags.CpuVisible = 1;
2182 pAllocationInfo->Size = pAllocation->AllocData.SurfDesc.cbSize;
2183
2184 pAllocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_HIGH;
2185 }
2186 else
2187 Status = STATUS_UNSUCCESSFUL;
2188 }
2189 else
2190#endif
2191 {
2192 RT_NOREF(pDevExt);
2193
2194 Assert(pAllocation->AllocData.SurfDesc.bpp);
2195 Assert(pAllocation->AllocData.SurfDesc.pitch);
2196 Assert(pAllocation->AllocData.SurfDesc.cbSize);
2197
2198 /*
2199 * Mark the allocation as visible to the CPU so we can
2200 * lock it in the user mode driver for SYSTEM pool allocations.
2201 * See @bugref{8040} for further information.
2202 */
2203 if (!pAllocInfo->fFlags.SharedResource && !pAllocInfo->hostID)
2204 pAllocationInfo->Flags.CpuVisible = 1;
2205
2206 if (pAllocInfo->fFlags.SharedResource)
2207 {
2208 pAllocation->hSharedHandle = (HANDLE)pAllocInfo->hSharedHandle;
2209#if 0
2210 if (pAllocation->hSharedHandle)
2211 {
2212 vboxShRcTreePut(pDevExt, pAllocation);
2213 }
2214#endif
2215 }
2216
2217#if 0
2218 /* Allocation from the CPU invisible second segment does not
2219 * work apparently and actually fails on Vista.
2220 *
2221 * @todo Find out what exactly is wrong.
2222 */
2223// if (pAllocInfo->hostID)
2224 {
2225 pAllocationInfo->SupportedReadSegmentSet = 2;
2226 pAllocationInfo->SupportedWriteSegmentSet = 2;
2227 }
2228#endif
2229 }
2230 break;
2231 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE:
2232 case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE:
2233 if (SvgaIsDXSupported(pDevExt))
2234 {
2235 pAllocationInfo->PreferredSegment.Value = 0;
2236 pAllocationInfo->SupportedReadSegmentSet = 1; /* VRAM */
2237 pAllocationInfo->SupportedWriteSegmentSet = 1; /* VRAM */
2238 }
2239 pAllocationInfo->Flags.CpuVisible = 1;
2240 break;
2241 default: AssertFailedBreak(); /* Shut up MSC.*/
2242 }
2243
2244 if (Status == STATUS_SUCCESS)
2245 {
2246 pAllocation->UsageHint.Version = 0;
2247 pAllocation->UsageHint.v1.Flags.Value = 0;
2248 pAllocation->UsageHint.v1.Format = pAllocInfo->SurfDesc.format;
2249 pAllocation->UsageHint.v1.SwizzledFormat = 0;
2250 pAllocation->UsageHint.v1.ByteOffset = 0;
2251 pAllocation->UsageHint.v1.Width = pAllocation->AllocData.SurfDesc.width;
2252 pAllocation->UsageHint.v1.Height = pAllocation->AllocData.SurfDesc.height;
2253 pAllocation->UsageHint.v1.Pitch = pAllocation->AllocData.SurfDesc.pitch;
2254 pAllocation->UsageHint.v1.Depth = 0;
2255 pAllocation->UsageHint.v1.SlicePitch = 0;
2256
2257 Assert(!pAllocationInfo->pAllocationUsageHint);
2258 pAllocationInfo->pAllocationUsageHint = &pAllocation->UsageHint;
2259 }
2260
2261 break;
2262 }
2263 case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER:
2264 {
2265 pAllocationInfo->Size = pAllocInfo->cbBuffer;
2266 pAllocation->fUhgsmiType = pAllocInfo->fUhgsmiType;
2267 pAllocation->AllocData.SurfDesc.cbSize = pAllocInfo->cbBuffer;
2268 pAllocationInfo->Flags.CpuVisible = 1;
2269// pAllocationInfo->Flags.SynchronousPaging = 1;
2270 pAllocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_MAXIMUM;
2271 break;
2272 }
2273
2274 default:
2275 LOGREL(("ERROR: invalid alloc info type(%d)", pAllocInfo->enmType));
2276 AssertBreakpoint();
2277 Status = STATUS_INVALID_PARAMETER;
2278 break;
2279
2280 }
2281
2282 if (Status != STATUS_SUCCESS)
2283 vboxWddmAllocationDeleteFromResource(pResource, pAllocation);
2284 }
2285 else
2286 {
2287 LOGREL(("ERROR: failed to create allocation description"));
2288 Status = STATUS_NO_MEMORY;
2289 }
2290
2291 }
2292 else
2293 {
2294 LOGREL(("ERROR: PrivateDriverDataSize(%d) less than header size(%d)", pAllocationInfo->PrivateDriverDataSize, sizeof (VBOXWDDM_ALLOCINFO)));
2295 Status = STATUS_INVALID_PARAMETER;
2296 }
2297
2298 return Status;
2299}
2300
2301NTSTATUS APIENTRY DxgkDdiCreateAllocation(
2302 CONST HANDLE hAdapter,
2303 DXGKARG_CREATEALLOCATION* pCreateAllocation)
2304{
2305 /* DxgkDdiCreateAllocation should be made pageable. */
2306 PAGED_CODE();
2307
2308 LOGF(("ENTER, context(0x%x)", hAdapter));
2309
2310 vboxVDbgBreakFv();
2311
2312#ifdef VBOX_WITH_VMSVGA3D_DX
2313 /* The driver distinguished between the legacy and the new D3D(DX) requests by checking the size. */
2314 AssertCompile(sizeof(VBOXDXALLOCATIONDESC) != sizeof(VBOXWDDM_ALLOCINFO));
2315
2316 /* Check if this is a request from the new D3D driver. */
2317 if ( pCreateAllocation->PrivateDriverDataSize == 0
2318 && pCreateAllocation->NumAllocations == 1
2319 && pCreateAllocation->pAllocationInfo[0].PrivateDriverDataSize == sizeof(VBOXDXALLOCATIONDESC))
2320 return DxgkDdiDXCreateAllocation(hAdapter, pCreateAllocation);
2321#endif
2322
2323 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
2324 NTSTATUS Status = STATUS_SUCCESS;
2325 PVBOXWDDM_RESOURCE pResource = NULL;
2326
2327 if (pCreateAllocation->PrivateDriverDataSize)
2328 {
2329 Assert(pCreateAllocation->PrivateDriverDataSize == sizeof (VBOXWDDM_RCINFO));
2330 Assert(pCreateAllocation->pPrivateDriverData);
2331 if (pCreateAllocation->PrivateDriverDataSize < sizeof (VBOXWDDM_RCINFO))
2332 {
2333 WARN(("invalid private data size (%d)", pCreateAllocation->PrivateDriverDataSize));
2334 return STATUS_INVALID_PARAMETER;
2335 }
2336
2337 PVBOXWDDM_RCINFO pRcInfo = (PVBOXWDDM_RCINFO)pCreateAllocation->pPrivateDriverData;
2338// Assert(pRcInfo->RcDesc.VidPnSourceId < VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
2339 if (pRcInfo->cAllocInfos != pCreateAllocation->NumAllocations)
2340 {
2341 WARN(("invalid number of allocations passed in, (%d), expected (%d)", pRcInfo->cAllocInfos, pCreateAllocation->NumAllocations));
2342 return STATUS_INVALID_PARAMETER;
2343 }
2344
2345 /* a check to ensure we do not get the allocation size which is too big to overflow the 32bit value */
2346 if (VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXWDDM_RESOURCE, aAllocations) < pRcInfo->cAllocInfos)
2347 {
2348 WARN(("number of allocations passed too big (%d), max is (%d)", pRcInfo->cAllocInfos, VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXWDDM_RESOURCE, aAllocations)));
2349 return STATUS_INVALID_PARAMETER;
2350 }
2351
2352 pResource = (PVBOXWDDM_RESOURCE)vboxWddmMemAllocZero(RT_UOFFSETOF_DYN(VBOXWDDM_RESOURCE, aAllocations[pRcInfo->cAllocInfos]));
2353 if (!pResource)
2354 {
2355 WARN(("vboxWddmMemAllocZero failed for (%d) allocations", pRcInfo->cAllocInfos));
2356 return STATUS_NO_MEMORY;
2357 }
2358
2359 pResource->cRefs = 1;
2360 pResource->cAllocations = pRcInfo->cAllocInfos;
2361 pResource->fFlags = pRcInfo->fFlags;
2362 pResource->RcDesc = pRcInfo->RcDesc;
2363 }
2364
2365
2366 for (UINT i = 0; i < pCreateAllocation->NumAllocations; ++i)
2367 {
2368 Status = vboxWddmAllocationCreate(pDevExt, pResource, i, &pCreateAllocation->pAllocationInfo[i]);
2369 if (Status != STATUS_SUCCESS)
2370 {
2371 WARN(("vboxWddmAllocationCreate(%d) failed, Status(0x%x)", i, Status));
2372 /* note: i-th allocation is expected to be cleared in a fail handling code above */
2373 for (UINT j = 0; j < i; ++j)
2374 {
2375 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pCreateAllocation->pAllocationInfo[j].hAllocation;
2376 vboxWddmAllocationCleanup(pDevExt, pAllocation);
2377 vboxWddmAllocationDestroy(pAllocation);
2378 }
2379 break;
2380 }
2381 }
2382
2383 if (Status == STATUS_SUCCESS)
2384 {
2385 pCreateAllocation->hResource = pResource;
2386 }
2387 else
2388 {
2389 if (pResource)
2390 vboxWddmResourceRelease(pResource);
2391 }
2392
2393 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
2394
2395 return Status;
2396}
2397
2398NTSTATUS
2399APIENTRY
2400DxgkDdiDestroyAllocation(
2401 CONST HANDLE hAdapter,
2402 CONST DXGKARG_DESTROYALLOCATION* pDestroyAllocation)
2403{
2404 /* DxgkDdiDestroyAllocation should be made pageable. */
2405 PAGED_CODE();
2406
2407 LOGF(("ENTER, context(0x%x)", hAdapter));
2408
2409 vboxVDbgBreakFv();
2410
2411 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
2412
2413 for (UINT i = 0; i < pDestroyAllocation->NumAllocations; ++i)
2414 {
2415 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pDestroyAllocation->pAllocationList[0];
2416 if (pAllocation->CurVidPnSourceId != -1)
2417 {
2418 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAllocation->CurVidPnSourceId];
2419 vboxWddmAssignPrimary(pSource, NULL, pAllocation->CurVidPnSourceId);
2420 }
2421 }
2422
2423#ifdef VBOX_WITH_VMSVGA3D_DX
2424 /* Check if this is a request from the D3D driver. */
2425 if (pDestroyAllocation->NumAllocations >= 1)
2426 {
2427 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pDestroyAllocation->pAllocationList[0];
2428 if (pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_D3D)
2429 return DxgkDdiDXDestroyAllocation(hAdapter, pDestroyAllocation);
2430 }
2431#endif
2432
2433 NTSTATUS Status = STATUS_SUCCESS;
2434
2435 PVBOXWDDM_RESOURCE pRc = (PVBOXWDDM_RESOURCE)pDestroyAllocation->hResource;
2436 if (pRc)
2437 {
2438 Assert(pRc->cAllocations == pDestroyAllocation->NumAllocations);
2439 }
2440
2441 for (UINT i = 0; i < pDestroyAllocation->NumAllocations; ++i)
2442 {
2443 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pDestroyAllocation->pAllocationList[i];
2444 Assert(pAlloc->pResource == pRc);
2445 vboxWddmAllocationCleanupAssignment(pDevExt, pAlloc);
2446 /* wait for all current allocation-related ops are completed */
2447 vboxWddmAllocationCleanup(pDevExt, pAlloc);
2448 vboxWddmAllocationDestroy(pAlloc);
2449 }
2450
2451 if (pRc)
2452 {
2453 /* wait for all current resource-related ops are completed */
2454 vboxWddmResourceWaitDereference(pRc);
2455 vboxWddmResourceRelease(pRc);
2456 }
2457
2458 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
2459
2460 return Status;
2461}
2462
2463/**
2464 * DxgkDdiDescribeAllocation
2465 */
2466NTSTATUS
2467APIENTRY
2468DxgkDdiDescribeAllocation(
2469 CONST HANDLE hAdapter,
2470 DXGKARG_DESCRIBEALLOCATION* pDescribeAllocation)
2471{
2472 RT_NOREF(hAdapter);
2473// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2474
2475 vboxVDbgBreakFv();
2476
2477 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pDescribeAllocation->hAllocation;
2478#ifdef VBOX_WITH_VMSVGA3D_DX
2479 /* Check if this is a request from the D3D driver. */
2480 if (pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_D3D)
2481 return DxgkDdiDXDescribeAllocation(hAdapter, pDescribeAllocation);
2482#endif
2483 pDescribeAllocation->Width = pAllocation->AllocData.SurfDesc.width;
2484 pDescribeAllocation->Height = pAllocation->AllocData.SurfDesc.height;
2485 pDescribeAllocation->Format = pAllocation->AllocData.SurfDesc.format;
2486 memset (&pDescribeAllocation->MultisampleMethod, 0, sizeof (pDescribeAllocation->MultisampleMethod));
2487 pDescribeAllocation->RefreshRate.Numerator = g_RefreshRate * 1000;
2488 pDescribeAllocation->RefreshRate.Denominator = 1000;
2489 pDescribeAllocation->PrivateDriverFormatAttribute = 0;
2490
2491// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2492
2493 return STATUS_SUCCESS;
2494}
2495
2496/**
2497 * DxgkDdiGetStandardAllocationDriverData
2498 */
2499NTSTATUS
2500APIENTRY
2501DxgkDdiGetStandardAllocationDriverData(
2502 CONST HANDLE hAdapter,
2503 DXGKARG_GETSTANDARDALLOCATIONDRIVERDATA* pGetStandardAllocationDriverData)
2504{
2505 RT_NOREF(hAdapter);
2506 /* DxgkDdiGetStandardAllocationDriverData should be made pageable. */
2507 PAGED_CODE();
2508
2509 LOGF(("ENTER, context(0x%x)", hAdapter));
2510
2511 vboxVDbgBreakFv();
2512
2513 NTSTATUS Status = STATUS_SUCCESS;
2514 PVBOXWDDM_ALLOCINFO pAllocInfo = NULL;
2515
2516 switch (pGetStandardAllocationDriverData->StandardAllocationType)
2517 {
2518 case D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE:
2519 {
2520 LOGF(("D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE"));
2521 if(pGetStandardAllocationDriverData->pAllocationPrivateDriverData)
2522 {
2523 pAllocInfo = (PVBOXWDDM_ALLOCINFO)pGetStandardAllocationDriverData->pAllocationPrivateDriverData;
2524 memset (pAllocInfo, 0, sizeof (VBOXWDDM_ALLOCINFO));
2525 pAllocInfo->enmType = VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE;
2526 pAllocInfo->SurfDesc.width = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Width;
2527 pAllocInfo->SurfDesc.height = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Height;
2528 pAllocInfo->SurfDesc.format = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Format;
2529 pAllocInfo->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pAllocInfo->SurfDesc.format);
2530 pAllocInfo->SurfDesc.pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Width, pAllocInfo->SurfDesc.format);
2531 pAllocInfo->SurfDesc.cbSize = vboxWddmCalcSize(pAllocInfo->SurfDesc.pitch, pAllocInfo->SurfDesc.height, pAllocInfo->SurfDesc.format);
2532 pAllocInfo->SurfDesc.depth = 0;
2533 pAllocInfo->SurfDesc.slicePitch = 0;
2534 pAllocInfo->SurfDesc.RefreshRate = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->RefreshRate;
2535 pAllocInfo->SurfDesc.VidPnSourceId = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->VidPnSourceId;
2536 }
2537 pGetStandardAllocationDriverData->AllocationPrivateDriverDataSize = sizeof (VBOXWDDM_ALLOCINFO);
2538
2539 pGetStandardAllocationDriverData->ResourcePrivateDriverDataSize = 0;
2540 break;
2541 }
2542 case D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE:
2543 {
2544 LOGF(("D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE"));
2545 UINT bpp = vboxWddmCalcBitsPerPixel(pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format);
2546 Assert(bpp);
2547 if (bpp != 0)
2548 {
2549 UINT Pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Width, pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format);
2550 pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Pitch = Pitch;
2551
2552 /** @todo need [d/q]word align?? */
2553
2554 if (pGetStandardAllocationDriverData->pAllocationPrivateDriverData)
2555 {
2556 pAllocInfo = (PVBOXWDDM_ALLOCINFO)pGetStandardAllocationDriverData->pAllocationPrivateDriverData;
2557 pAllocInfo->enmType = VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE;
2558 pAllocInfo->SurfDesc.width = pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Width;
2559 pAllocInfo->SurfDesc.height = pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Height;
2560 pAllocInfo->SurfDesc.format = pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format;
2561 pAllocInfo->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pAllocInfo->SurfDesc.format);
2562 pAllocInfo->SurfDesc.pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Width, pAllocInfo->SurfDesc.format);
2563 pAllocInfo->SurfDesc.cbSize = vboxWddmCalcSize(pAllocInfo->SurfDesc.pitch, pAllocInfo->SurfDesc.height, pAllocInfo->SurfDesc.format);
2564 pAllocInfo->SurfDesc.depth = 0;
2565 pAllocInfo->SurfDesc.slicePitch = 0;
2566 pAllocInfo->SurfDesc.RefreshRate.Numerator = 0;
2567 pAllocInfo->SurfDesc.RefreshRate.Denominator = 1000;
2568 pAllocInfo->SurfDesc.VidPnSourceId = D3DDDI_ID_UNINITIALIZED;
2569
2570 pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Pitch = pAllocInfo->SurfDesc.pitch;
2571 }
2572 pGetStandardAllocationDriverData->AllocationPrivateDriverDataSize = sizeof (VBOXWDDM_ALLOCINFO);
2573
2574 pGetStandardAllocationDriverData->ResourcePrivateDriverDataSize = 0;
2575 }
2576 else
2577 {
2578 LOGREL(("Invalid format (%d)", pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format));
2579 Status = STATUS_INVALID_PARAMETER;
2580 }
2581 break;
2582 }
2583 case D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE:
2584 {
2585 LOGF(("D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE"));
2586 if(pGetStandardAllocationDriverData->pAllocationPrivateDriverData)
2587 {
2588 pAllocInfo = (PVBOXWDDM_ALLOCINFO)pGetStandardAllocationDriverData->pAllocationPrivateDriverData;
2589 pAllocInfo->enmType = VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE;
2590 pAllocInfo->SurfDesc.width = pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Width;
2591 pAllocInfo->SurfDesc.height = pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Height;
2592 pAllocInfo->SurfDesc.format = D3DDDIFMT_X8R8G8B8; /* staging has always always D3DDDIFMT_X8R8G8B8 */
2593 pAllocInfo->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pAllocInfo->SurfDesc.format);
2594 pAllocInfo->SurfDesc.pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Width, pAllocInfo->SurfDesc.format);
2595 pAllocInfo->SurfDesc.cbSize = vboxWddmCalcSize(pAllocInfo->SurfDesc.pitch, pAllocInfo->SurfDesc.height, pAllocInfo->SurfDesc.format);
2596 pAllocInfo->SurfDesc.depth = 0;
2597 pAllocInfo->SurfDesc.slicePitch = 0;
2598 pAllocInfo->SurfDesc.RefreshRate.Numerator = 0;
2599 pAllocInfo->SurfDesc.RefreshRate.Denominator = 1000;
2600 pAllocInfo->SurfDesc.VidPnSourceId = D3DDDI_ID_UNINITIALIZED;
2601
2602 pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Pitch = pAllocInfo->SurfDesc.pitch;
2603 }
2604 pGetStandardAllocationDriverData->AllocationPrivateDriverDataSize = sizeof (VBOXWDDM_ALLOCINFO);
2605
2606 pGetStandardAllocationDriverData->ResourcePrivateDriverDataSize = 0;
2607 break;
2608 }
2609//#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN7)
2610// case D3DKMDT_STANDARDALLOCATION_GDISURFACE:
2611//# error port to Win7 DDI
2612// break;
2613//#endif
2614 default:
2615 LOGREL(("Invalid allocation type (%d)", pGetStandardAllocationDriverData->StandardAllocationType));
2616 Status = STATUS_INVALID_PARAMETER;
2617 break;
2618 }
2619
2620 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
2621
2622 return Status;
2623}
2624
2625NTSTATUS
2626APIENTRY
2627DxgkDdiAcquireSwizzlingRange(
2628 CONST HANDLE hAdapter,
2629 DXGKARG_ACQUIRESWIZZLINGRANGE* pAcquireSwizzlingRange)
2630{
2631 RT_NOREF(hAdapter, pAcquireSwizzlingRange);
2632 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2633
2634 AssertBreakpoint();
2635
2636 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2637
2638 return STATUS_SUCCESS;
2639}
2640
2641NTSTATUS
2642APIENTRY
2643DxgkDdiReleaseSwizzlingRange(
2644 CONST HANDLE hAdapter,
2645 CONST DXGKARG_RELEASESWIZZLINGRANGE* pReleaseSwizzlingRange)
2646{
2647 RT_NOREF(hAdapter, pReleaseSwizzlingRange);
2648 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2649
2650 AssertBreakpoint();
2651
2652 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2653
2654 return STATUS_SUCCESS;
2655}
2656
2657typedef struct VBOXWDDM_CALL_ISR
2658{
2659 PVBOXMP_DEVEXT pDevExt;
2660 ULONG MessageNumber;
2661} VBOXWDDM_CALL_ISR, *PVBOXWDDM_CALL_ISR;
2662
2663static BOOLEAN vboxWddmCallIsrCb(PVOID Context)
2664{
2665 PVBOXWDDM_CALL_ISR pdc = (PVBOXWDDM_CALL_ISR)Context;
2666 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
2667 if (pDevExt->fCmdVbvaEnabled)
2668 {
2669#ifdef DEBUG_sunlover
2670 /** @todo Remove VBOX_WITH_VIDEOHWACCEL code, because the host does not support it anymore. */
2671 AssertFailed(); /* Should not be here, because this is not used with 3D gallium driver. */
2672#endif
2673 return FALSE;
2674 }
2675 return DxgkDdiInterruptRoutineLegacy(pDevExt, pdc->MessageNumber);
2676}
2677
2678NTSTATUS vboxWddmCallIsr(PVBOXMP_DEVEXT pDevExt)
2679{
2680 VBOXWDDM_CALL_ISR context;
2681 context.pDevExt = pDevExt;
2682 context.MessageNumber = 0;
2683 BOOLEAN bRet;
2684 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
2685 pDevExt->u.primary.DxgkInterface.DeviceHandle,
2686 vboxWddmCallIsrCb,
2687 &context,
2688 0, /* IN ULONG MessageNumber */
2689 &bRet);
2690 AssertNtStatusSuccess(Status);
2691 return Status;
2692}
2693
2694
2695NTSTATUS
2696APIENTRY
2697DxgkDdiSetPalette(
2698 CONST HANDLE hAdapter,
2699 CONST DXGKARG_SETPALETTE* pSetPalette
2700 )
2701{
2702 RT_NOREF(hAdapter, pSetPalette);
2703 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2704
2705 AssertBreakpoint();
2706 /** @todo fixme: implement */
2707
2708 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2709
2710 return STATUS_SUCCESS;
2711}
2712
2713/** Find which area of a 32 bit mouse pointer bitmap is actually used.
2714 * Zero pixels on the right and the bottom of the bitmap are considered unused.
2715 *
2716 * @param pPixels The bitmap.
2717 * @param Pitch The bitmap scanline size in bytes.
2718 * @param Width The bitmap width.
2719 * @param Height The bitmap height.
2720 * @param piMaxFilledPixel Where to store the maximum index of non-zero pixel within a scanline.
2721 * @param piMaxFilledScanline Where to store the zero based index of the last scanline with non-zero pixels.
2722 */
2723static void vboxWddmPointerFindDimensionsColor(void const *pPixels, UINT Pitch, UINT Width, UINT Height,
2724 LONG *piMaxFilledPixel, LONG *piMaxFilledScanline)
2725{
2726 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2727 * Exclude zero pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2728 */
2729 DWORD const *pdwScanline = (DWORD *)pPixels;
2730 LONG iMaxFilledScanline = -1;
2731 LONG iMaxFilledPixel = -1;
2732 for (ULONG y = 0; y < Height; ++y)
2733 {
2734 LONG iLastFilledPixel = -1;
2735 for (ULONG x = 0; x < Width; ++x)
2736 {
2737 if (pdwScanline[x])
2738 iLastFilledPixel = x;
2739 }
2740
2741 iMaxFilledPixel = RT_MAX(iMaxFilledPixel, iLastFilledPixel);
2742
2743 if (iLastFilledPixel >= 0)
2744 {
2745 /* Scanline contains non-zero pixels. */
2746 iMaxFilledScanline = y;
2747 }
2748
2749 pdwScanline = (DWORD *)((uint8_t *)pdwScanline + Pitch);
2750 }
2751
2752 *piMaxFilledPixel = iMaxFilledPixel;
2753 *piMaxFilledScanline = iMaxFilledScanline;
2754}
2755
2756/** Find which area of a 1 bit AND/XOR mask bitmap is actually used, i.e. filled with actual data.
2757 * For the AND mask the bytes with a value 0xff on the right and the bottom of the bitmap are considered unused.
2758 * For the XOR mask the blank value is 0x00.
2759 *
2760 * @param pPixels The 1bit bitmap.
2761 * @param Pitch The 1bit bitmap scanline size in bytes.
2762 * @param Width The bitmap width.
2763 * @param Height The bitmap height.
2764 * @param Blank The value of the unused bytes in the supplied bitmap.
2765 * @param piMaxFilledPixel Where to store the maximum index of a filled pixel within a scanline.
2766 * @param piMaxFilledScanline Where to store the zero based index of the last scanline with filled pixels.
2767 */
2768static void vboxWddmPointerFindDimensionsMono(void const *pPixels, UINT Pitch, UINT Width, UINT Height, BYTE Blank,
2769 LONG *piMaxFilledPixel, LONG *piMaxFilledScanline)
2770{
2771 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2772 * Exclude the blank pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2773 */
2774 BYTE const *pbScanline = (BYTE *)pPixels;
2775 LONG iMaxFilledScanline = -1;
2776 LONG iMaxFilledByte = -1;
2777 for (ULONG y = 0; y < Height; ++y)
2778 {
2779 LONG iLastFilledByte = -1;
2780 for (ULONG x = 0; x < Width / 8; ++x)
2781 {
2782 if (pbScanline[x] != Blank)
2783 iLastFilledByte = x;
2784 }
2785
2786 iMaxFilledByte = RT_MAX(iMaxFilledByte, iLastFilledByte);
2787
2788 if (iLastFilledByte >= 0)
2789 {
2790 /* Scanline contains filled pixels. */
2791 iMaxFilledScanline = y;
2792 }
2793
2794 pbScanline += Pitch;
2795 }
2796
2797 *piMaxFilledPixel = iMaxFilledByte * 8;
2798 *piMaxFilledScanline = iMaxFilledScanline;
2799}
2800
2801/** Adjust the width and the height of the mouse pointer bitmap.
2802 * See comments in the function for the adjustment criteria.
2803 *
2804 * @param iMaxX The index of the rightmost pixel which we want to keep.
2805 * @param iMaxY The index of the bottom-most pixel which we want to keep.
2806 * @param XHot The mouse pointer hot spot.
2807 * @param YHot The mouse pointer hot spot.
2808 * @param pWidth Where to store the bitmap width.
2809 * @param pHeight Where to store the bitmap height.
2810 */
2811static void vboxWddmPointerAdjustDimensions(LONG iMaxX, LONG iMaxY, UINT XHot, UINT YHot,
2812 ULONG *pWidth, ULONG *pHeight)
2813{
2814 /* Both input parameters are zero based indexes, add 1 to get a width and a height. */
2815 ULONG W = iMaxX + 1;
2816 ULONG H = iMaxY + 1;
2817
2818 /* Always include the hotspot point. */
2819 W = RT_MAX(XHot, W);
2820 H = RT_MAX(YHot, H);
2821
2822 /* Align to 8 pixels, because the XOR/AND pointers are aligned like that.
2823 * The AND mask has one bit per pixel with 8 bits per byte.
2824 * In case the host can't deal with unaligned data.
2825 */
2826 W = RT_ALIGN_T(W, 8, ULONG);
2827 H = RT_ALIGN_T(H, 8, ULONG);
2828
2829 /* Do not send bitmaps with zero dimensions. Actually make the min size 32x32. */
2830 W = RT_MAX(32, W);
2831 H = RT_MAX(32, H);
2832
2833 /* Make it square. Some hosts are known to require square pointers. */
2834 W = RT_MAX(W, H);
2835 H = W;
2836
2837 /* Do not exceed the supported size.
2838 * Actually this should not be necessary because Windows never creates such pointers.
2839 */
2840 W = RT_MIN(W, VBOXWDDM_C_POINTER_MAX_WIDTH);
2841 H = RT_MIN(H, VBOXWDDM_C_POINTER_MAX_HEIGHT);
2842
2843 *pWidth = W;
2844 *pHeight = H;
2845}
2846
2847BOOL vboxWddmPointerCopyColorData(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVIDEO_POINTER_ATTRIBUTES pPointerAttributes,
2848 bool fDwordAlignScanlines)
2849{
2850 ULONG srcMaskW, srcMaskH;
2851 ULONG dstBytesPerLine;
2852 ULONG x, y;
2853 BYTE *pSrc, *pDst, bit;
2854
2855 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2856 * Exclude zero pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2857 */
2858 LONG iMaxFilledPixel;
2859 LONG iMaxFilledScanline;
2860 vboxWddmPointerFindDimensionsColor(pSetPointerShape->pPixels, pSetPointerShape->Pitch,
2861 pSetPointerShape->Width, pSetPointerShape->Height,
2862 &iMaxFilledPixel, &iMaxFilledScanline);
2863
2864 vboxWddmPointerAdjustDimensions(iMaxFilledPixel, iMaxFilledScanline,
2865 pSetPointerShape->XHot, pSetPointerShape->YHot,
2866 &srcMaskW, &srcMaskH);
2867
2868 pPointerAttributes->Width = srcMaskW;
2869 pPointerAttributes->Height = srcMaskH;
2870 pPointerAttributes->WidthInBytes = pPointerAttributes->Width * 4;
2871
2872 /* cnstruct and mask from alpha color channel */
2873 pSrc = (PBYTE)pSetPointerShape->pPixels;
2874 pDst = pPointerAttributes->Pixels;
2875 dstBytesPerLine = (pPointerAttributes->Width+7)/8;
2876 if (fDwordAlignScanlines)
2877 dstBytesPerLine = RT_ALIGN_T(dstBytesPerLine, 4, ULONG);
2878
2879 /* sanity check */
2880 uint32_t cbData = RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG)+
2881 pPointerAttributes->Height*pPointerAttributes->WidthInBytes;
2882 uint32_t cbPointerAttributes = RT_UOFFSETOF_DYN(VIDEO_POINTER_ATTRIBUTES, Pixels[cbData]);
2883 Assert(VBOXWDDM_POINTER_ATTRIBUTES_SIZE >= cbPointerAttributes);
2884 if (VBOXWDDM_POINTER_ATTRIBUTES_SIZE < cbPointerAttributes)
2885 {
2886 LOGREL(("VBOXWDDM_POINTER_ATTRIBUTES_SIZE(%d) < cbPointerAttributes(%d)", VBOXWDDM_POINTER_ATTRIBUTES_SIZE, cbPointerAttributes));
2887 return FALSE;
2888 }
2889
2890 memset(pDst, 0xFF, dstBytesPerLine*pPointerAttributes->Height);
2891 for (y=0; y<pPointerAttributes->Height; ++y)
2892 {
2893 for (x=0, bit=7; x<pPointerAttributes->Width; ++x, --bit)
2894 {
2895 if (0xFF==bit) bit=7;
2896
2897 if (pSrc[y*pSetPointerShape->Pitch + x*4 + 3] > 0x7F)
2898 {
2899 pDst[y*dstBytesPerLine + x/8] &= ~RT_BIT(bit);
2900 }
2901 }
2902 }
2903
2904 /* copy 32bpp to XOR DIB, it start in pPointerAttributes->Pixels should be 4bytes aligned */
2905 pSrc = (BYTE*)pSetPointerShape->pPixels;
2906 pDst = pPointerAttributes->Pixels + RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG);
2907 dstBytesPerLine = pPointerAttributes->Width * 4;
2908
2909 for (y=0; y<pPointerAttributes->Height; ++y)
2910 {
2911 memcpy(pDst+y*dstBytesPerLine, pSrc+y*pSetPointerShape->Pitch, dstBytesPerLine);
2912 }
2913
2914 return TRUE;
2915}
2916
2917BOOL vboxWddmPointerCopyMonoData(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVIDEO_POINTER_ATTRIBUTES pPointerAttributes,
2918 bool fDwordAlignScanlines)
2919{
2920 ULONG srcMaskW, srcMaskH;
2921 ULONG dstBytesPerLine;
2922 ULONG x, y;
2923 BYTE *pSrc, *pDst, bit;
2924
2925 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2926 * Exclude unused pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2927 */
2928 LONG iMaxFilledPixelAND;
2929 LONG iMaxFilledScanlineAND;
2930 vboxWddmPointerFindDimensionsMono(pSetPointerShape->pPixels, pSetPointerShape->Pitch,
2931 pSetPointerShape->Width, pSetPointerShape->Height, 0xff,
2932 &iMaxFilledPixelAND, &iMaxFilledScanlineAND);
2933
2934 LONG iMaxFilledPixelXOR;
2935 LONG iMaxFilledScanlineXOR;
2936 vboxWddmPointerFindDimensionsMono((BYTE *)pSetPointerShape->pPixels + pSetPointerShape->Height * pSetPointerShape->Pitch,
2937 pSetPointerShape->Pitch,
2938 pSetPointerShape->Width, pSetPointerShape->Height, 0x00,
2939 &iMaxFilledPixelXOR, &iMaxFilledScanlineXOR);
2940
2941 LONG iMaxFilledPixel = RT_MAX(iMaxFilledPixelAND, iMaxFilledPixelXOR);
2942 LONG iMaxFilledScanline = RT_MAX(iMaxFilledScanlineAND, iMaxFilledScanlineXOR);
2943
2944 vboxWddmPointerAdjustDimensions(iMaxFilledPixel, iMaxFilledScanline,
2945 pSetPointerShape->XHot, pSetPointerShape->YHot,
2946 &srcMaskW, &srcMaskH);
2947
2948 pPointerAttributes->Width = srcMaskW;
2949 pPointerAttributes->Height = srcMaskH;
2950 pPointerAttributes->WidthInBytes = pPointerAttributes->Width * 4;
2951
2952 /* copy AND mask */
2953 pSrc = (PBYTE)pSetPointerShape->pPixels;
2954 pDst = pPointerAttributes->Pixels;
2955 dstBytesPerLine = (pPointerAttributes->Width+7)/8;
2956 if (fDwordAlignScanlines)
2957 dstBytesPerLine = RT_ALIGN_T(dstBytesPerLine, 4, ULONG);
2958
2959 for (y=0; y<pPointerAttributes->Height; ++y)
2960 {
2961 memcpy(pDst+y*dstBytesPerLine, pSrc+y*pSetPointerShape->Pitch, dstBytesPerLine);
2962 }
2963
2964 /* convert XOR mask to RGB0 DIB, it start in pPointerAttributes->Pixels should be 4bytes aligned */
2965 pSrc = (BYTE*)pSetPointerShape->pPixels + pSetPointerShape->Height*pSetPointerShape->Pitch;
2966 pDst = pPointerAttributes->Pixels + RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG);
2967 dstBytesPerLine = pPointerAttributes->Width * 4;
2968
2969 for (y=0; y<pPointerAttributes->Height; ++y)
2970 {
2971 for (x=0, bit=7; x<pPointerAttributes->Width; ++x, --bit)
2972 {
2973 if (0xFF==bit) bit=7;
2974
2975 *(ULONG*)&pDst[y*dstBytesPerLine+x*4] = (pSrc[y*pSetPointerShape->Pitch+x/8] & RT_BIT(bit)) ? 0x00FFFFFF : 0;
2976 }
2977 }
2978
2979 return TRUE;
2980}
2981
2982static BOOLEAN vboxVddmPointerShapeToAttributes(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVBOXWDDM_POINTER_INFO pPointerInfo,
2983 bool fDwordAlignScanlines)
2984{
2985 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = &pPointerInfo->Attributes.data;
2986 /* pPointerAttributes maintains the visibility state, clear all except visibility */
2987 pPointerAttributes->Enable &= VBOX_MOUSE_POINTER_VISIBLE;
2988
2989 Assert(pSetPointerShape->Flags.Value == 1 || pSetPointerShape->Flags.Value == 2);
2990 if (pSetPointerShape->Flags.Color)
2991 {
2992 if (vboxWddmPointerCopyColorData(pSetPointerShape, pPointerAttributes, fDwordAlignScanlines))
2993 {
2994 pPointerAttributes->Flags = VIDEO_MODE_COLOR_POINTER;
2995 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_ALPHA;
2996 }
2997 else
2998 {
2999 LOGREL(("vboxWddmPointerCopyColorData failed"));
3000 AssertBreakpoint();
3001 return FALSE;
3002 }
3003
3004 }
3005 else if (pSetPointerShape->Flags.Monochrome)
3006 {
3007 if (vboxWddmPointerCopyMonoData(pSetPointerShape, pPointerAttributes, fDwordAlignScanlines))
3008 {
3009 pPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER;
3010 }
3011 else
3012 {
3013 LOGREL(("vboxWddmPointerCopyMonoData failed"));
3014 AssertBreakpoint();
3015 return FALSE;
3016 }
3017 }
3018 else
3019 {
3020 LOGREL(("unsupported pointer type Flags.Value(0x%x)", pSetPointerShape->Flags.Value));
3021 AssertBreakpoint();
3022 return FALSE;
3023 }
3024
3025 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_SHAPE;
3026
3027 /*
3028 * The hot spot coordinates and alpha flag will be encoded in the pPointerAttributes::Enable field.
3029 * High word will contain hot spot info and low word - flags.
3030 */
3031 pPointerAttributes->Enable |= (pSetPointerShape->YHot & 0xFF) << 24;
3032 pPointerAttributes->Enable |= (pSetPointerShape->XHot & 0xFF) << 16;
3033
3034 return TRUE;
3035}
3036
3037bool vboxWddmUpdatePointerShape(PVBOXMP_DEVEXT pDevExt, PVIDEO_POINTER_ATTRIBUTES pAttrs, uint32_t cbLength)
3038{
3039#ifdef VBOX_WITH_VMSVGA
3040 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VBOX)
3041 {
3042 NTSTATUS Status = STATUS_SUCCESS;
3043
3044 /** @todo Get rid of the unnecesary en-/decode procedure (XPDM legacy). */
3045 uint32_t fFlags = pAttrs->Enable & 0x0000FFFF;
3046 uint32_t xHot = (pAttrs->Enable >> 16) & 0xFF;
3047 uint32_t yHot = (pAttrs->Enable >> 24) & 0xFF;
3048 uint32_t cWidth = pAttrs->Width;
3049 uint32_t cHeight = pAttrs->Height;
3050 uint32_t cbAndMask = 0;
3051 uint32_t cbXorMask = 0;
3052
3053 if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
3054 {
3055 /* Size of the pointer data: sizeof(AND mask) + sizeof(XOR mask) */
3056 /* "Each scanline is padded to a 32-bit boundary." */
3057 cbAndMask = ((((cWidth + 7) / 8) + 3) & ~3) * cHeight;
3058 cbXorMask = cWidth * 4 * cHeight;
3059
3060 /* Send the shape to the host. */
3061 if (fFlags & VBOX_MOUSE_POINTER_ALPHA)
3062 {
3063 void const *pvImage = &pAttrs->Pixels[cbAndMask];
3064 Status = GaDefineAlphaCursor(pDevExt->pGa,
3065 xHot,
3066 yHot,
3067 cWidth,
3068 cHeight,
3069 pvImage,
3070 cbXorMask);
3071 }
3072 else
3073 {
3074 uint32_t u32AndMaskDepth = 1;
3075 uint32_t u32XorMaskDepth = 32;
3076
3077 void const *pvAndMask = &pAttrs->Pixels[0];
3078 void const *pvXorMask = &pAttrs->Pixels[cbAndMask];
3079 Status = GaDefineCursor(pDevExt->pGa,
3080 xHot,
3081 yHot,
3082 cWidth,
3083 cHeight,
3084 u32AndMaskDepth,
3085 u32XorMaskDepth,
3086 pvAndMask,
3087 cbAndMask,
3088 pvXorMask,
3089 cbXorMask);
3090 }
3091 }
3092
3093 /** @todo Hack: Use the legacy interface to handle visibility.
3094 * Eventually the VMSVGA WDDM driver should use the SVGA_FIFO_CURSOR_* interface.
3095 */
3096 VIDEO_POINTER_ATTRIBUTES attrs;
3097 RT_ZERO(attrs);
3098 attrs.Enable = pAttrs->Enable & VBOX_MOUSE_POINTER_VISIBLE;
3099 if (!VBoxMPCmnUpdatePointerShape(VBoxCommonFromDeviceExt(pDevExt), &attrs, sizeof(attrs)))
3100 {
3101 Status = STATUS_INVALID_PARAMETER;
3102 }
3103
3104 return Status == STATUS_SUCCESS;
3105 }
3106#endif
3107
3108 /* VBOXVIDEO_HWTYPE_VBOX */
3109 return VBoxMPCmnUpdatePointerShape(VBoxCommonFromDeviceExt(pDevExt), pAttrs, cbLength);
3110}
3111
3112static void vboxWddmHostPointerEnable(PVBOXMP_DEVEXT pDevExt, BOOLEAN fEnable)
3113{
3114 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
3115 RT_ZERO(PointerAttributes);
3116 if (fEnable)
3117 {
3118 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
3119 }
3120 vboxWddmUpdatePointerShape(pDevExt, &PointerAttributes, sizeof(PointerAttributes));
3121}
3122
3123NTSTATUS
3124APIENTRY
3125DxgkDdiSetPointerPosition(
3126 CONST HANDLE hAdapter,
3127 CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
3128{
3129// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3130
3131 vboxVDbgBreakFv();
3132
3133 /* mouse integration is ON */
3134 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3135 PVBOXWDDM_POINTER_INFO pPointerInfo = &pDevExt->aSources[pSetPointerPosition->VidPnSourceId].PointerInfo;
3136 PVBOXWDDM_GLOBAL_POINTER_INFO pGlobalPointerInfo = &pDevExt->PointerInfo;
3137 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = &pPointerInfo->Attributes.data;
3138 BOOLEAN fScreenVisState = !!(pPointerAttributes->Enable & VBOX_MOUSE_POINTER_VISIBLE);
3139 BOOLEAN fVisStateChanged = FALSE;
3140 BOOLEAN fScreenChanged = pGlobalPointerInfo->iLastReportedScreen != pSetPointerPosition->VidPnSourceId;
3141
3142 if (pSetPointerPosition->Flags.Visible)
3143 {
3144 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_VISIBLE;
3145 if (!fScreenVisState)
3146 {
3147 fVisStateChanged = TRUE;
3148 }
3149 }
3150 else
3151 {
3152 pPointerAttributes->Enable &= ~VBOX_MOUSE_POINTER_VISIBLE;
3153 if (fScreenVisState)
3154 {
3155 fVisStateChanged = TRUE;
3156 }
3157 }
3158
3159 pGlobalPointerInfo->iLastReportedScreen = pSetPointerPosition->VidPnSourceId;
3160
3161 if ((fVisStateChanged || fScreenChanged) && VBoxQueryHostWantsAbsolute())
3162 {
3163 if (fScreenChanged)
3164 {
3165 BOOLEAN bResult = vboxWddmUpdatePointerShape(pDevExt, &pPointerInfo->Attributes.data, VBOXWDDM_POINTER_ATTRIBUTES_SIZE);
3166 if (!bResult)
3167 {
3168 vboxWddmHostPointerEnable(pDevExt, FALSE);
3169 }
3170 }
3171
3172 // Always update the visibility as requested. Tell the host to use the guest's pointer.
3173 vboxWddmHostPointerEnable(pDevExt, pSetPointerPosition->Flags.Visible);
3174 }
3175
3176// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3177
3178 return STATUS_SUCCESS;
3179}
3180
3181NTSTATUS
3182APIENTRY
3183DxgkDdiSetPointerShape(
3184 CONST HANDLE hAdapter,
3185 CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
3186{
3187// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3188
3189 vboxVDbgBreakFv();
3190
3191 NTSTATUS Status = STATUS_NOT_SUPPORTED;
3192
3193 if (VBoxQueryHostWantsAbsolute())
3194 {
3195 /* mouse integration is ON */
3196 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3197 PVBOXWDDM_POINTER_INFO pPointerInfo = &pDevExt->aSources[pSetPointerShape->VidPnSourceId].PointerInfo;
3198 bool const fDwordAlignScanlines = pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VBOX;
3199 /** @todo to avoid extra data copy and extra heap allocation,
3200 * need to maintain the pre-allocated HGSMI buffer and convert the data directly to it */
3201 if (vboxVddmPointerShapeToAttributes(pSetPointerShape, pPointerInfo, fDwordAlignScanlines))
3202 {
3203 pDevExt->PointerInfo.iLastReportedScreen = pSetPointerShape->VidPnSourceId;
3204 if (vboxWddmUpdatePointerShape(pDevExt, &pPointerInfo->Attributes.data, VBOXWDDM_POINTER_ATTRIBUTES_SIZE))
3205 Status = STATUS_SUCCESS;
3206 else
3207 {
3208 // tell the host to use the guest's pointer
3209 vboxWddmHostPointerEnable(pDevExt, FALSE);
3210 }
3211 }
3212 }
3213
3214// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3215
3216 return Status;
3217}
3218
3219NTSTATUS
3220APIENTRY CALLBACK
3221DxgkDdiResetFromTimeout(
3222 CONST HANDLE hAdapter)
3223{
3224 RT_NOREF(hAdapter);
3225 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3226
3227 AssertBreakpoint();
3228 /** @todo fixme: implement */
3229
3230 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3231
3232 return STATUS_SUCCESS;
3233}
3234
3235
3236/* the lpRgnData->Buffer comes to us as RECT
3237 * to avoid extra memcpy we cast it to PRTRECT assuming
3238 * they are identical */
3239AssertCompile(sizeof(RECT) == sizeof(RTRECT));
3240AssertCompile(RT_OFFSETOF(RECT, left) == RT_OFFSETOF(RTRECT, xLeft));
3241AssertCompile(RT_OFFSETOF(RECT, bottom) == RT_OFFSETOF(RTRECT, yBottom));
3242AssertCompile(RT_OFFSETOF(RECT, right) == RT_OFFSETOF(RTRECT, xRight));
3243AssertCompile(RT_OFFSETOF(RECT, top) == RT_OFFSETOF(RTRECT, yTop));
3244
3245NTSTATUS
3246APIENTRY
3247DxgkDdiEscape(
3248 CONST HANDLE hAdapter,
3249 CONST DXGKARG_ESCAPE* pEscape)
3250{
3251 PAGED_CODE();
3252
3253// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3254
3255 NTSTATUS Status = STATUS_NOT_SUPPORTED;
3256 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3257 Assert(pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE));
3258 if (pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE))
3259 {
3260 PVBOXDISPIFESCAPE pEscapeHdr = (PVBOXDISPIFESCAPE)pEscape->pPrivateDriverData;
3261 switch (pEscapeHdr->escapeCode)
3262 {
3263 case VBOXESC_SETVISIBLEREGION:
3264 {
3265#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3266 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3267 if (!pContext)
3268 {
3269 WARN(("VBOXESC_SETVISIBLEREGION no context supplied!"));
3270 Status = STATUS_INVALID_PARAMETER;
3271 break;
3272 }
3273
3274 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS)
3275 {
3276 WARN(("VBOXESC_SETVISIBLEREGION invalid context supplied %d!", pContext->enmType));
3277 Status = STATUS_INVALID_PARAMETER;
3278 break;
3279 }
3280#endif
3281 /* visible regions for seamless */
3282 LPRGNDATA lpRgnData = VBOXDISPIFESCAPE_DATA(pEscapeHdr, RGNDATA);
3283 uint32_t cbData = VBOXDISPIFESCAPE_DATA_SIZE(pEscape->PrivateDriverDataSize);
3284 uint32_t cbRects = cbData - RT_UOFFSETOF(RGNDATA, Buffer);
3285 /* the lpRgnData->Buffer comes to us as RECT
3286 * to avoid extra memcpy we cast it to PRTRECT assuming
3287 * they are identical
3288 * see AssertCompile's above */
3289
3290 RTRECT *pRect = (RTRECT *)&lpRgnData->Buffer;
3291
3292 uint32_t cRects = cbRects/sizeof(RTRECT);
3293 int rc;
3294
3295 LOG(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRects=%d", cRects));
3296 Assert(cbRects >= sizeof(RTRECT)
3297 && cbRects == cRects*sizeof(RTRECT)
3298 && cRects == lpRgnData->rdh.nCount);
3299 if ( cbRects >= sizeof(RTRECT)
3300 && cbRects == cRects*sizeof(RTRECT)
3301 && cRects == lpRgnData->rdh.nCount)
3302 {
3303 /*
3304 * Inform the host about the visible region
3305 */
3306 VMMDevVideoSetVisibleRegion *pReq = NULL;
3307
3308 rc = VbglR0GRAlloc ((VMMDevRequestHeader **)&pReq,
3309 sizeof (VMMDevVideoSetVisibleRegion) + (cRects-1)*sizeof(RTRECT),
3310 VMMDevReq_VideoSetVisibleRegion);
3311 AssertRC(rc);
3312 if (RT_SUCCESS(rc))
3313 {
3314 pReq->cRect = cRects;
3315 memcpy(&pReq->Rect, pRect, cRects*sizeof(RTRECT));
3316
3317 rc = VbglR0GRPerform (&pReq->header);
3318 AssertRC(rc);
3319 if (RT_SUCCESS(rc))
3320 Status = STATUS_SUCCESS;
3321 else
3322 {
3323 WARN(("VbglR0GRPerform failed rc (%d)", rc));
3324 Status = STATUS_UNSUCCESSFUL;
3325 }
3326 VbglR0GRFree(&pReq->header);
3327 }
3328 else
3329 {
3330 WARN(("VbglR0GRAlloc failed rc (%d)", rc));
3331 Status = STATUS_UNSUCCESSFUL;
3332 }
3333 }
3334 else
3335 {
3336 WARN(("VBOXESC_SETVISIBLEREGION: incorrect buffer size (%d), reported count (%d)", cbRects, lpRgnData->rdh.nCount));
3337 Status = STATUS_INVALID_PARAMETER;
3338 }
3339 break;
3340 }
3341 case VBOXESC_ISVRDPACTIVE:
3342 /** @todo implement */
3343 Status = STATUS_SUCCESS;
3344 break;
3345 case VBOXESC_CONFIGURETARGETS:
3346 {
3347 LOG(("=> VBOXESC_CONFIGURETARGETS"));
3348
3349 if (!pEscape->Flags.HardwareAccess)
3350 {
3351 WARN(("VBOXESC_CONFIGURETARGETS called without HardwareAccess flag set, failing"));
3352 Status = STATUS_INVALID_PARAMETER;
3353 break;
3354 }
3355
3356#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3357 /* win8.1 does not allow context-based escapes for display-only mode */
3358 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3359 if (!pContext)
3360 {
3361 WARN(("VBOXESC_CONFIGURETARGETS no context supplied!"));
3362 Status = STATUS_INVALID_PARAMETER;
3363 break;
3364 }
3365
3366 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE)
3367 {
3368 WARN(("VBOXESC_CONFIGURETARGETS invalid context supplied %d!", pContext->enmType));
3369 Status = STATUS_INVALID_PARAMETER;
3370 break;
3371 }
3372#endif
3373
3374 if (pEscape->PrivateDriverDataSize != sizeof (*pEscapeHdr))
3375 {
3376 WARN(("VBOXESC_CONFIGURETARGETS invalid private driver size %d", pEscape->PrivateDriverDataSize));
3377 Status = STATUS_INVALID_PARAMETER;
3378 break;
3379 }
3380
3381 if (pEscapeHdr->u32CmdSpecific)
3382 {
3383 WARN(("VBOXESC_CONFIGURETARGETS invalid command %d", pEscapeHdr->u32CmdSpecific));
3384 Status = STATUS_INVALID_PARAMETER;
3385 break;
3386 }
3387
3388 HANDLE hKey = NULL;
3389 uint32_t cAdjusted = 0;
3390
3391 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3392 {
3393 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
3394 if (pTarget->fConfigured)
3395 continue;
3396
3397 pTarget->fConfigured = true;
3398
3399 if (!pTarget->fConnected)
3400 {
3401 Status = VBoxWddmChildStatusConnect(pDevExt, (uint32_t)i, TRUE);
3402 if (NT_SUCCESS(Status))
3403 ++cAdjusted;
3404 else
3405 WARN(("VBOXESC_CONFIGURETARGETS vboxWddmChildStatusConnectSecondaries failed Status 0x%x\n", Status));
3406 }
3407
3408 if (!hKey)
3409 {
3410 Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE, &hKey);
3411 if (!NT_SUCCESS(Status))
3412 {
3413 WARN(("VBOXESC_CONFIGURETARGETS IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
3414 hKey = NULL;
3415 continue;
3416 }
3417 }
3418
3419 Assert(hKey);
3420
3421 WCHAR wszNameBuf[sizeof(VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX) / sizeof(WCHAR) + 32];
3422 RTUtf16Printf(wszNameBuf, RT_ELEMENTS(wszNameBuf), "%ls%d", VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX, i);
3423 Status = vboxWddmRegSetValueDword(hKey, wszNameBuf, VBOXWDDM_CFG_DRVTARGET_CONNECTED);
3424 if (!NT_SUCCESS(Status))
3425 WARN(("VBOXESC_CONFIGURETARGETS vboxWddmRegSetValueDword (%ls) failed Status 0x%x\n", wszNameBuf, Status));
3426
3427 }
3428
3429 if (hKey)
3430 {
3431 NTSTATUS rcNt2 = ZwClose(hKey);
3432 Assert(rcNt2 == STATUS_SUCCESS); NOREF(rcNt2);
3433 }
3434
3435 pEscapeHdr->u32CmdSpecific = cAdjusted;
3436
3437 Status = STATUS_SUCCESS;
3438
3439 LOG(("<= VBOXESC_CONFIGURETARGETS"));
3440 break;
3441 }
3442 case VBOXESC_SETALLOCHOSTID:
3443 {
3444 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)pEscape->hDevice;
3445 if (!pDevice)
3446 {
3447 WARN(("VBOXESC_SETALLOCHOSTID called without no device specified, failing"));
3448 Status = STATUS_INVALID_PARAMETER;
3449 break;
3450 }
3451
3452 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_SETALLOCHOSTID))
3453 {
3454 WARN(("invalid buffer size for VBOXDISPIFESCAPE_SETALLOCHOSTID, was(%d), but expected (%d)",
3455 pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE_SETALLOCHOSTID)));
3456 Status = STATUS_INVALID_PARAMETER;
3457 break;
3458 }
3459
3460 if (!pEscape->Flags.HardwareAccess)
3461 {
3462 WARN(("VBOXESC_SETALLOCHOSTID not HardwareAccess"));
3463 Status = STATUS_INVALID_PARAMETER;
3464 break;
3465 }
3466
3467 PVBOXDISPIFESCAPE_SETALLOCHOSTID pSetHostID = (PVBOXDISPIFESCAPE_SETALLOCHOSTID)pEscapeHdr;
3468 PVBOXWDDM_ALLOCATION pAlloc = vboxWddmGetAllocationFromHandle(pDevExt, (D3DKMT_HANDLE)pSetHostID->hAlloc);
3469 if (!pAlloc)
3470 {
3471 WARN(("failed to get allocation from handle"));
3472 Status = STATUS_INVALID_PARAMETER;
3473 break;
3474 }
3475
3476 if (pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_D3D)
3477 {
3478 pSetHostID->EscapeHdr.u32CmdSpecific = pAlloc->dx.sid;
3479 pSetHostID->rc = VERR_NOT_EQUAL;
3480 Status = STATUS_SUCCESS;
3481 break;
3482 }
3483
3484 if (pAlloc->enmType != VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE)
3485 {
3486 WARN(("setHostID: invalid allocation type: %d", pAlloc->enmType));
3487 Status = STATUS_INVALID_PARAMETER;
3488 break;
3489 }
3490
3491 pSetHostID->rc = VBoxWddmOaSetHostID(pDevice, pAlloc, pSetHostID->hostID, &pSetHostID->EscapeHdr.u32CmdSpecific);
3492
3493 if (pAlloc->bAssigned)
3494 {
3495 PVBOXMP_DEVEXT pDevExt2 = pDevice->pAdapter;
3496 Assert(pAlloc->AllocData.SurfDesc.VidPnSourceId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt2)->cDisplays);
3497 PVBOXWDDM_SOURCE pSource = &pDevExt2->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
3498 if (pSource->AllocData.hostID != pAlloc->AllocData.hostID)
3499 {
3500 pSource->AllocData.hostID = pAlloc->AllocData.hostID;
3501 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
3502
3503 vboxWddmGhDisplayCheckSetInfo(pDevExt2);
3504 }
3505 }
3506
3507 Status = STATUS_SUCCESS;
3508 break;
3509 }
3510 case VBOXESC_ISANYX:
3511 {
3512 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_ISANYX))
3513 {
3514 WARN(("invalid private driver size %d", pEscape->PrivateDriverDataSize));
3515 Status = STATUS_INVALID_PARAMETER;
3516 break;
3517 }
3518
3519 PVBOXDISPIFESCAPE_ISANYX pIsAnyX = (PVBOXDISPIFESCAPE_ISANYX)pEscapeHdr;
3520 pIsAnyX->u32IsAnyX = VBoxCommonFromDeviceExt(pDevExt)->fAnyX;
3521 Status = STATUS_SUCCESS;
3522 break;
3523 }
3524 case VBOXESC_UPDATEMODES:
3525 {
3526 LOG(("=> VBOXESC_UPDATEMODES"));
3527
3528 if (!pEscape->Flags.HardwareAccess)
3529 {
3530 WARN(("VBOXESC_UPDATEMODES called without HardwareAccess flag set, failing"));
3531 Status = STATUS_INVALID_PARAMETER;
3532 break;
3533 }
3534
3535#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3536 /* win8.1 does not allow context-based escapes for display-only mode */
3537 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3538 if (!pContext)
3539 {
3540 WARN(("VBOXESC_UPDATEMODES no context supplied!"));
3541 Status = STATUS_INVALID_PARAMETER;
3542 break;
3543 }
3544
3545 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE)
3546 {
3547 WARN(("VBOXESC_UPDATEMODES invalid context supplied %d!", pContext->enmType));
3548 Status = STATUS_INVALID_PARAMETER;
3549 break;
3550 }
3551#endif
3552
3553 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_UPDATEMODES))
3554 {
3555 WARN(("VBOXESC_UPDATEMODES invalid private driver size %d", pEscape->PrivateDriverDataSize));
3556 Status = STATUS_INVALID_PARAMETER;
3557 break;
3558 }
3559
3560 VBOXDISPIFESCAPE_UPDATEMODES *pData = (VBOXDISPIFESCAPE_UPDATEMODES*)pEscapeHdr;
3561 Status = VBoxVidPnUpdateModes(pDevExt, pData->u32TargetId, &pData->Size);
3562 if (!NT_SUCCESS(Status))
3563 {
3564 WARN(("VBoxVidPnUpdateModes failed Status(%#x)\n", Status));
3565 return Status;
3566 }
3567
3568 Status = STATUS_SUCCESS;
3569 break;
3570 }
3571 case VBOXESC_TARGET_CONNECTIVITY:
3572 {
3573 if (!pEscape->Flags.HardwareAccess)
3574 {
3575 WARN(("VBOXESC_TARGET_CONNECTIVITY called without HardwareAccess flag set, failing"));
3576 Status = STATUS_INVALID_PARAMETER;
3577 break;
3578 }
3579
3580 if (pEscape->PrivateDriverDataSize != sizeof(VBOXDISPIFESCAPE_TARGETCONNECTIVITY))
3581 {
3582 WARN(("VBOXESC_TARGET_CONNECTIVITY invalid private driver size %d", pEscape->PrivateDriverDataSize));
3583 Status = STATUS_INVALID_PARAMETER;
3584 break;
3585 }
3586
3587 VBOXDISPIFESCAPE_TARGETCONNECTIVITY *pData = (VBOXDISPIFESCAPE_TARGETCONNECTIVITY *)pEscapeHdr;
3588 LOG(("=> VBOXESC_TARGET_CONNECTIVITY[%d] 0x%08X", pData->u32TargetId, pData->fu32Connect));
3589
3590 if (pData->u32TargetId >= (uint32_t)VBoxCommonFromDeviceExt(pDevExt)->cDisplays)
3591 {
3592 WARN(("VBOXESC_TARGET_CONNECTIVITY invalid screen index 0x%x", pData->u32TargetId));
3593 Status = STATUS_INVALID_PARAMETER;
3594 break;
3595 }
3596
3597 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[pData->u32TargetId];
3598 pTarget->fDisabled = !RT_BOOL(pData->fu32Connect & 1);
3599 pTarget->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_TOPOLOGY;
3600
3601 Status = STATUS_SUCCESS;
3602 break;
3603 }
3604 case VBOXESC_DBGPRINT:
3605 {
3606 /* use RT_OFFSETOF instead of sizeof since sizeof will give an aligned size that might
3607 * be bigger than the VBOXDISPIFESCAPE_DBGPRINT with a data containing just a few chars */
3608 Assert(pEscape->PrivateDriverDataSize >= RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]));
3609 /* only do DbgPrint when pEscape->PrivateDriverDataSize > RT_OFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1])
3610 * since == RT_OFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]) means the buffer contains just \0,
3611 * i.e. no need to print it */
3612 if (pEscape->PrivateDriverDataSize > RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]))
3613 {
3614 PVBOXDISPIFESCAPE_DBGPRINT pDbgPrint = (PVBOXDISPIFESCAPE_DBGPRINT)pEscapeHdr;
3615 /* ensure the last char is \0*/
3616 if (*((uint8_t*)pDbgPrint + pEscape->PrivateDriverDataSize - 1) == '\0')
3617 {
3618 if (g_VBoxLogUm & VBOXWDDM_CFG_LOG_UM_DBGPRINT)
3619 DbgPrint("%s\n", pDbgPrint->aStringBuf);
3620 if (g_VBoxLogUm & VBOXWDDM_CFG_LOG_UM_BACKDOOR)
3621 LOGREL_EXACT(("%s\n", pDbgPrint->aStringBuf));
3622 }
3623 }
3624 Status = STATUS_SUCCESS;
3625 break;
3626 }
3627 case VBOXESC_DBGDUMPBUF:
3628 {
3629 Status = vboxUmdDumpBuf((PVBOXDISPIFESCAPE_DBGDUMPBUF)pEscapeHdr, pEscape->PrivateDriverDataSize);
3630 break;
3631 }
3632 case VBOXESC_GUEST_DISPLAYCHANGED:
3633 {
3634 LOG(("=> VBOXESC_GUEST_DISPLAYCHANGED"));
3635
3636 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3637 {
3638#ifdef VBOX_WITH_VMSVGA
3639 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3640 {
3641 GaVidPnSourceCheckPos(pDevExt, i);
3642 continue;
3643 }
3644#endif
3645
3646 vboxWddmDisplaySettingsCheckPos(pDevExt, i);
3647 }
3648 Status = STATUS_SUCCESS;
3649 break;
3650 }
3651 default:
3652#ifdef VBOX_WITH_VMSVGA
3653 Status = GaDxgkDdiEscape(hAdapter, pEscape);
3654 if (NT_SUCCESS(Status) || Status != STATUS_NOT_SUPPORTED)
3655 break;
3656#endif
3657 WARN(("unsupported escape code (0x%x)", pEscapeHdr->escapeCode));
3658 break;
3659 }
3660 }
3661 else
3662 {
3663 WARN(("pEscape->PrivateDriverDataSize(%d) < (%d)", pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE)));
3664 Status = STATUS_BUFFER_TOO_SMALL;
3665 }
3666
3667// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3668
3669 return Status;
3670}
3671
3672NTSTATUS
3673APIENTRY
3674DxgkDdiCollectDbgInfo(
3675 CONST HANDLE hAdapter,
3676 CONST DXGKARG_COLLECTDBGINFO* pCollectDbgInfo
3677 )
3678{
3679 RT_NOREF(hAdapter, pCollectDbgInfo);
3680 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3681
3682 AssertBreakpoint();
3683
3684 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3685
3686 return STATUS_SUCCESS;
3687}
3688
3689NTSTATUS
3690APIENTRY
3691DxgkDdiIsSupportedVidPn(
3692 CONST HANDLE hAdapter,
3693 OUT DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPnArg
3694 )
3695{
3696 /* The DxgkDdiIsSupportedVidPn should be made pageable. */
3697 PAGED_CODE();
3698
3699 LOGF(("ENTER, context(0x%x)", hAdapter));
3700
3701 vboxVDbgBreakFv();
3702
3703 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3704 NTSTATUS Status = VBoxVidPnIsSupported(pDevExt, pIsSupportedVidPnArg->hDesiredVidPn, &pIsSupportedVidPnArg->IsVidPnSupported);
3705 if (!NT_SUCCESS(Status))
3706 {
3707 WARN(("VBoxVidPnIsSupported failed Status(%#x)\n", Status));
3708 return Status;
3709 }
3710
3711 LOGF(("LEAVE, isSupported(%d), context(0x%x)", pIsSupportedVidPnArg->IsVidPnSupported, hAdapter));
3712
3713 return STATUS_SUCCESS;
3714}
3715
3716NTSTATUS
3717APIENTRY
3718DxgkDdiRecommendFunctionalVidPn(
3719 CONST HANDLE hAdapter,
3720 CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPnArg
3721 )
3722{
3723 /* The DxgkDdiRecommendFunctionalVidPn should be made pageable. */
3724 PAGED_CODE();
3725
3726 LOGF(("ENTER, context(0x%x)", hAdapter));
3727
3728 vboxVDbgBreakFv();
3729
3730 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3731
3732 if (pRecommendFunctionalVidPnArg->PrivateDriverDataSize != sizeof (VBOXWDDM_RECOMMENDVIDPN))
3733 {
3734 WARN(("invalid size"));
3735 return STATUS_INVALID_PARAMETER;
3736 }
3737
3738 VBOXWDDM_RECOMMENDVIDPN *pData = (VBOXWDDM_RECOMMENDVIDPN*)pRecommendFunctionalVidPnArg->pPrivateDriverData;
3739 Assert(pData);
3740
3741 NTSTATUS Status = VBoxVidPnRecommendFunctional(pDevExt, pRecommendFunctionalVidPnArg->hRecommendedFunctionalVidPn, pData);
3742 if (!NT_SUCCESS(Status))
3743 {
3744 WARN(("VBoxVidPnRecommendFunctional failed %#x", Status));
3745 return Status;
3746 }
3747
3748 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3749
3750 return STATUS_SUCCESS;
3751}
3752
3753NTSTATUS
3754APIENTRY
3755DxgkDdiEnumVidPnCofuncModality(
3756 CONST HANDLE hAdapter,
3757 CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModalityArg
3758 )
3759{
3760 /* The DxgkDdiEnumVidPnCofuncModality function should be made pageable. */
3761 PAGED_CODE();
3762
3763 LOGF(("ENTER, context(0x%x)", hAdapter));
3764
3765 vboxVDbgBreakFv();
3766
3767 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3768
3769 NTSTATUS Status = VBoxVidPnCofuncModality(pDevExt, pEnumCofuncModalityArg->hConstrainingVidPn, pEnumCofuncModalityArg->EnumPivotType, &pEnumCofuncModalityArg->EnumPivot);
3770 if (!NT_SUCCESS(Status))
3771 {
3772 WARN(("VBoxVidPnCofuncModality failed Status(%#x)\n", Status));
3773 return Status;
3774 }
3775
3776 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3777
3778 return STATUS_SUCCESS;
3779}
3780
3781NTSTATUS
3782APIENTRY
3783DxgkDdiSetVidPnSourceAddress(
3784 CONST HANDLE hAdapter,
3785 CONST DXGKARG_SETVIDPNSOURCEADDRESS* pSetVidPnSourceAddress
3786 )
3787{
3788 /* The DxgkDdiSetVidPnSourceAddress function should be made pageable. */
3789 PAGED_CODE();
3790
3791 vboxVDbgBreakFv();
3792
3793 LOGF(("ENTER, context(0x%x)", hAdapter));
3794 LOG(("id %d, seg %d, addr 0x%RX64, hAllocation %p, ctx cnt %d, f 0x%x",
3795 pSetVidPnSourceAddress->VidPnSourceId,
3796 pSetVidPnSourceAddress->PrimarySegment,
3797 pSetVidPnSourceAddress->PrimaryAddress.QuadPart,
3798 pSetVidPnSourceAddress->hAllocation,
3799 pSetVidPnSourceAddress->ContextCount,
3800 pSetVidPnSourceAddress->Flags.Value));
3801
3802 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3803 if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceAddress->VidPnSourceId)
3804 {
3805 WARN(("invalid VidPnSourceId (%d), for displays(%d)", pSetVidPnSourceAddress->VidPnSourceId, VBoxCommonFromDeviceExt(pDevExt)->cDisplays));
3806 return STATUS_INVALID_PARAMETER;
3807 }
3808
3809#ifdef VBOX_WITH_VMSVGA
3810 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VMSVGA)
3811#endif
3812 vboxWddmDisplaySettingsCheckPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId);
3813
3814 NTSTATUS Status = STATUS_SUCCESS;
3815 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceAddress->VidPnSourceId];
3816
3817 /*
3818 * Update the source VRAM address.
3819 */
3820 PVBOXWDDM_ALLOCATION pAllocation;
3821 Assert(pSetVidPnSourceAddress->hAllocation);
3822 Assert(pSetVidPnSourceAddress->hAllocation || pSource->pPrimaryAllocation);
3823 Assert (pSetVidPnSourceAddress->Flags.Value < 2); /* i.e. 0 or 1 (ModeChange) */
3824
3825 if (pSetVidPnSourceAddress->hAllocation)
3826 {
3827 pAllocation = (PVBOXWDDM_ALLOCATION)pSetVidPnSourceAddress->hAllocation;
3828 vboxWddmAssignPrimary(pSource, pAllocation, pSetVidPnSourceAddress->VidPnSourceId);
3829 }
3830 else
3831 pAllocation = pSource->pPrimaryAllocation;
3832
3833 if (pAllocation)
3834 {
3835 vboxWddmAddrSetVram(&pAllocation->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment, (VBOXVIDEOOFFSET)pSetVidPnSourceAddress->PrimaryAddress.QuadPart);
3836 }
3837
3838 if (g_VBoxDisplayOnly && !pAllocation)
3839 {
3840 /* the VRAM here is an absolute address, nto an offset!
3841 * convert to offset since all internal VBox functionality is offset-based */
3842 vboxWddmAddrSetVram(&pSource->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment,
3843 vboxWddmVramAddrToOffset(pDevExt, pSetVidPnSourceAddress->PrimaryAddress));
3844 }
3845 else
3846 {
3847 Assert(!g_VBoxDisplayOnly);
3848 vboxWddmAddrSetVram(&pSource->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment,
3849 pSetVidPnSourceAddress->PrimaryAddress.QuadPart);
3850 }
3851
3852 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
3853
3854 /*
3855 * Report the source.
3856 */
3857#ifdef VBOX_WITH_VMSVGA
3858 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3859 {
3860 /* Query the position of the screen to make sure it is up to date. */
3861 vboxWddmDisplaySettingsQueryPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId, &pSource->VScreenPos);
3862
3863 GaVidPnSourceReport(pDevExt, pSource);
3864 return STATUS_SUCCESS;
3865 }
3866#endif
3867
3868 vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
3869
3870 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3871
3872 return Status;
3873}
3874
3875NTSTATUS
3876APIENTRY
3877DxgkDdiSetVidPnSourceVisibility(
3878 CONST HANDLE hAdapter,
3879 CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility
3880 )
3881{
3882 /* DxgkDdiSetVidPnSourceVisibility should be made pageable. */
3883 PAGED_CODE();
3884
3885 vboxVDbgBreakFv();
3886
3887 LOGF(("ENTER, context(0x%x)", hAdapter));
3888
3889 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3890
3891 if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceVisibility->VidPnSourceId)
3892 {
3893 WARN(("invalid VidPnSourceId (%d), for displays(%d)", pSetVidPnSourceVisibility->VidPnSourceId, VBoxCommonFromDeviceExt(pDevExt)->cDisplays));
3894 return STATUS_INVALID_PARAMETER;
3895 }
3896
3897#ifdef VBOX_WITH_VMSVGA
3898 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VMSVGA)
3899#endif
3900 vboxWddmDisplaySettingsCheckPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId);
3901
3902 NTSTATUS Status = STATUS_SUCCESS;
3903 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceVisibility->VidPnSourceId];
3904 PVBOXWDDM_ALLOCATION pAllocation = pSource->pPrimaryAllocation;
3905 if (pAllocation)
3906 {
3907 Assert(pAllocation->bVisible == pSource->bVisible);
3908 pAllocation->bVisible = pSetVidPnSourceVisibility->Visible;
3909 }
3910
3911 if (pSource->bVisible != pSetVidPnSourceVisibility->Visible)
3912 {
3913 pSource->bVisible = pSetVidPnSourceVisibility->Visible;
3914// pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_VISIBILITY;
3915// if (pDevExt->fCmdVbvaEnabled || pSource->bVisible)
3916// {
3917// vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
3918// }
3919 }
3920
3921#ifdef VBOX_WITH_VMSVGA
3922 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3923 {
3924 GaVidPnSourceCheckPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId);
3925 }
3926#endif
3927
3928 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3929
3930 return Status;
3931}
3932
3933NTSTATUS
3934APIENTRY
3935DxgkDdiCommitVidPn(
3936 CONST HANDLE hAdapter,
3937 CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPnArg
3938 )
3939{
3940 LOG(("ENTER AffectedVidPnSourceId(%d) hAdapter(0x%x)", pCommitVidPnArg->AffectedVidPnSourceId, hAdapter));
3941
3942 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3943 NTSTATUS Status;
3944
3945 vboxVDbgBreakFv();
3946
3947 VBOXWDDM_SOURCE *paSources = (VBOXWDDM_SOURCE*)RTMemAlloc(sizeof (VBOXWDDM_SOURCE) * VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3948 if (!paSources)
3949 {
3950 WARN(("RTMemAlloc failed"));
3951 return STATUS_NO_MEMORY;
3952 }
3953
3954 VBOXWDDM_TARGET *paTargets = (VBOXWDDM_TARGET*)RTMemAlloc(sizeof (VBOXWDDM_TARGET) * VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3955 if (!paTargets)
3956 {
3957 WARN(("RTMemAlloc failed"));
3958 RTMemFree(paSources);
3959 return STATUS_NO_MEMORY;
3960 }
3961
3962 VBoxVidPnSourcesInit(paSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, VBOXWDDM_HGSYNC_F_SYNCED_ALL);
3963
3964 VBoxVidPnTargetsInit(paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, VBOXWDDM_HGSYNC_F_SYNCED_ALL);
3965
3966 VBoxVidPnSourcesCopy(paSources, pDevExt->aSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3967 VBoxVidPnTargetsCopy(paTargets, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3968
3969 do {
3970 const DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
3971 Status = pDevExt->u.primary.DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPnArg->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
3972 if (!NT_SUCCESS(Status))
3973 {
3974 WARN(("DxgkCbQueryVidPnInterface failed Status 0x%x", Status));
3975 break;
3976 }
3977
3978#ifdef VBOXWDDM_DEBUG_VIDPN
3979 vboxVidPnDumpVidPn("\n>>>>COMMIT VidPN: >>>>", pDevExt, pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface, "<<<<<<<<<<<<<<<<<<<<\n");
3980#endif
3981
3982 if (pCommitVidPnArg->AffectedVidPnSourceId != D3DDDI_ID_ALL)
3983 {
3984 Status = VBoxVidPnCommitSourceModeForSrcId(
3985 pDevExt,
3986 pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface,
3987 (PVBOXWDDM_ALLOCATION)pCommitVidPnArg->hPrimaryAllocation,
3988 pCommitVidPnArg->AffectedVidPnSourceId, paSources, paTargets, pCommitVidPnArg->Flags.PathPowerTransition);
3989 if (!NT_SUCCESS(Status))
3990 {
3991 WARN(("VBoxVidPnCommitSourceModeForSrcId for current VidPn failed Status 0x%x", Status));
3992 break;
3993 }
3994 }
3995 else
3996 {
3997 Status = VBoxVidPnCommitAll(pDevExt, pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface,
3998 (PVBOXWDDM_ALLOCATION)pCommitVidPnArg->hPrimaryAllocation,
3999 paSources, paTargets);
4000 if (!NT_SUCCESS(Status))
4001 {
4002 WARN(("VBoxVidPnCommitAll for current VidPn failed Status 0x%x", Status));
4003 break;
4004 }
4005 }
4006
4007 Assert(NT_SUCCESS(Status));
4008 pDevExt->u.primary.hCommittedVidPn = pCommitVidPnArg->hFunctionalVidPn;
4009 VBoxVidPnSourcesCopy(pDevExt->aSources, paSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
4010 VBoxVidPnTargetsCopy(pDevExt->aTargets, paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
4011
4012 VBoxDumpSourceTargetArrays(paSources, paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
4013
4014#ifdef VBOX_WITH_VMSVGA
4015 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4016 {
4017 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
4018 {
4019 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[i];
4020
4021 LOG(("Source [%d]: visible %d, blanked %d", i, pSource->bVisible, pSource->bBlankedByPowerOff));
4022
4023 /* Update positions of all screens. */
4024 vboxWddmDisplaySettingsQueryPos(pDevExt, i, &pSource->VScreenPos);
4025
4026 GaVidPnSourceReport(pDevExt, pSource);
4027 }
4028
4029 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
4030 {
4031 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
4032 Assert(pTarget->u32Id == (unsigned)i);
4033 if (pTarget->VidPnSourceId != D3DDDI_ID_UNINITIALIZED)
4034 {
4035 continue;
4036 }
4037
4038 LOG(("Target [%d]: blanked %d", i, pTarget->fBlankedByPowerOff));
4039
4040 if (pTarget->fBlankedByPowerOff)
4041 {
4042 GaScreenDefine(pDevExt->pGa, 0, pTarget->u32Id, 0, 0, 0, 0, true);
4043 }
4044 else
4045 {
4046 GaScreenDestroy(pDevExt->pGa, pTarget->u32Id);
4047 }
4048 }
4049
4050 break;
4051 }
4052#endif
4053 vboxWddmGhDisplayCheckSetInfo(pDevExt);
4054 } while (0);
4055
4056 RTMemFree(paSources);
4057 RTMemFree(paTargets);
4058
4059 LOG(("LEAVE, status(0x%x), hAdapter(0x%x)", Status, hAdapter));
4060
4061 return Status;
4062}
4063
4064NTSTATUS
4065APIENTRY
4066DxgkDdiUpdateActiveVidPnPresentPath(
4067 CONST HANDLE hAdapter,
4068 CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPathArg
4069 )
4070{
4071 RT_NOREF(hAdapter, pUpdateActiveVidPnPresentPathArg);
4072 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4073
4074 AssertBreakpoint();
4075
4076 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4077
4078 return STATUS_SUCCESS;
4079}
4080
4081NTSTATUS
4082APIENTRY
4083DxgkDdiRecommendMonitorModes(
4084 CONST HANDLE hAdapter,
4085 CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModesArg
4086 )
4087{
4088 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4089
4090 vboxVDbgBreakFv();
4091
4092 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4093
4094 NTSTATUS Status = VBoxVidPnRecommendMonitorModes(pDevExt, pRecommendMonitorModesArg->VideoPresentTargetId,
4095 pRecommendMonitorModesArg->hMonitorSourceModeSet, pRecommendMonitorModesArg->pMonitorSourceModeSetInterface);
4096 if (!NT_SUCCESS(Status))
4097 {
4098 WARN(("VBoxVidPnRecommendMonitorModes failed %#x", Status));
4099 return Status;
4100 }
4101
4102 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4103
4104 return STATUS_SUCCESS;
4105}
4106
4107NTSTATUS
4108APIENTRY
4109DxgkDdiRecommendVidPnTopology(
4110 CONST HANDLE hAdapter,
4111 CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopologyArg
4112 )
4113{
4114 RT_NOREF(hAdapter, pRecommendVidPnTopologyArg);
4115 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4116
4117 vboxVDbgBreakFv();
4118
4119 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4120
4121 return STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY;
4122}
4123
4124NTSTATUS
4125APIENTRY
4126DxgkDdiGetScanLine(
4127 CONST HANDLE hAdapter,
4128 DXGKARG_GETSCANLINE* pGetScanLine)
4129{
4130 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4131
4132 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4133
4134#ifdef DEBUG_misha
4135// RT_BREAKPOINT();
4136#endif
4137
4138 NTSTATUS Status = VBoxWddmSlGetScanLine(pDevExt, pGetScanLine);
4139
4140 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4141
4142 return Status;
4143}
4144
4145NTSTATUS
4146APIENTRY
4147DxgkDdiStopCapture(
4148 CONST HANDLE hAdapter,
4149 CONST DXGKARG_STOPCAPTURE* pStopCapture)
4150{
4151 RT_NOREF(hAdapter, pStopCapture);
4152 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4153
4154 AssertBreakpoint();
4155
4156 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4157
4158 return STATUS_SUCCESS;
4159}
4160
4161NTSTATUS
4162APIENTRY
4163DxgkDdiControlInterrupt(
4164 CONST HANDLE hAdapter,
4165 CONST DXGK_INTERRUPT_TYPE InterruptType,
4166 BOOLEAN Enable
4167 )
4168{
4169 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4170
4171 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
4172 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4173
4174 switch (InterruptType)
4175 {
4176 case DXGK_INTERRUPT_DISPLAYONLY_VSYNC:
4177 case DXGK_INTERRUPT_CRTC_VSYNC:
4178 {
4179 Status = VBoxWddmSlEnableVSyncNotification(pDevExt, Enable);
4180 if (NT_SUCCESS(Status))
4181 Status = STATUS_SUCCESS; /* <- sanity */
4182 else
4183 WARN(("VSYNC Interrupt control failed Enable(%d), Status(0x%x)", Enable, Status));
4184 break;
4185 }
4186 case DXGK_INTERRUPT_DMA_COMPLETED:
4187 case DXGK_INTERRUPT_DMA_PREEMPTED:
4188 case DXGK_INTERRUPT_DMA_FAULTED:
4189 WARN(("Unexpected interrupt type! %d", InterruptType));
4190 break;
4191 default:
4192 WARN(("UNSUPPORTED interrupt type! %d", InterruptType));
4193 break;
4194 }
4195
4196 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4197
4198 return Status;
4199}
4200
4201NTSTATUS
4202APIENTRY
4203DxgkDdiCreateOverlay(
4204 CONST HANDLE hAdapter,
4205 DXGKARG_CREATEOVERLAY *pCreateOverlay)
4206{
4207 LOGF(("ENTER, hAdapter(0x%p)", hAdapter));
4208
4209 NTSTATUS Status = STATUS_SUCCESS;
4210
4211#ifdef VBOX_WITH_VIDEOHWACCEL
4212 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4213 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)vboxWddmMemAllocZero(sizeof (VBOXWDDM_OVERLAY));
4214 Assert(pOverlay);
4215 if (pOverlay)
4216 {
4217 int rc = vboxVhwaHlpOverlayCreate(pDevExt, pCreateOverlay->VidPnSourceId, &pCreateOverlay->OverlayInfo, pOverlay);
4218 AssertRC(rc);
4219 if (RT_SUCCESS(rc))
4220 {
4221 pCreateOverlay->hOverlay = pOverlay;
4222 }
4223 else
4224 {
4225 vboxWddmMemFree(pOverlay);
4226 Status = STATUS_UNSUCCESSFUL;
4227 }
4228 }
4229 else
4230 Status = STATUS_NO_MEMORY;
4231#else
4232 RT_NOREF(hAdapter, pCreateOverlay);
4233#endif
4234
4235 LOGF(("LEAVE, hAdapter(0x%p)", hAdapter));
4236
4237 return Status;
4238}
4239
4240NTSTATUS
4241APIENTRY
4242DxgkDdiDestroyDevice(
4243 CONST HANDLE hDevice)
4244{
4245 /* DxgkDdiDestroyDevice should be made pageable. */
4246 PAGED_CODE();
4247
4248 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4249
4250 vboxVDbgBreakFv();
4251
4252#ifdef VBOX_WITH_VMSVGA
4253 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4254 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4255 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4256 {
4257 GaDeviceDestroy(pDevExt->pGa, pDevice);
4258 }
4259#endif
4260
4261 vboxWddmMemFree(hDevice);
4262
4263 LOGF(("LEAVE, "));
4264
4265 return STATUS_SUCCESS;
4266}
4267
4268
4269
4270/*
4271 * DxgkDdiOpenAllocation
4272 */
4273NTSTATUS
4274APIENTRY
4275DxgkDdiOpenAllocation(
4276 CONST HANDLE hDevice,
4277 CONST DXGKARG_OPENALLOCATION *pOpenAllocation)
4278{
4279 /* DxgkDdiOpenAllocation should be made pageable. */
4280 PAGED_CODE();
4281
4282 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4283
4284 vboxVDbgBreakFv();
4285
4286 NTSTATUS Status = STATUS_SUCCESS;
4287 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4288 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4289 PVBOXWDDM_RCINFO pRcInfo = NULL;
4290 if (pOpenAllocation->PrivateDriverSize)
4291 {
4292 Assert(pOpenAllocation->pPrivateDriverData);
4293 if (pOpenAllocation->PrivateDriverSize == sizeof (VBOXWDDM_RCINFO))
4294 {
4295 pRcInfo = (PVBOXWDDM_RCINFO)pOpenAllocation->pPrivateDriverData;
4296 Assert(pRcInfo->cAllocInfos == pOpenAllocation->NumAllocations);
4297 }
4298 else
4299 {
4300 WARN(("Invalid PrivateDriverSize %d", pOpenAllocation->PrivateDriverSize));
4301 Status = STATUS_INVALID_PARAMETER;
4302 }
4303 }
4304
4305 if (Status == STATUS_SUCCESS)
4306 {
4307 UINT i = 0;
4308 for (; i < pOpenAllocation->NumAllocations; ++i)
4309 {
4310 DXGK_OPENALLOCATIONINFO* pInfo = &pOpenAllocation->pOpenAllocation[i];
4311#ifdef VBOX_WITH_VMSVGA3D_DX
4312 Assert( pInfo->PrivateDriverDataSize == sizeof(VBOXDXALLOCATIONDESC)
4313 || pInfo->PrivateDriverDataSize == sizeof(VBOXWDDM_ALLOCINFO));
4314#else
4315 Assert(pInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_ALLOCINFO));
4316#endif
4317 Assert(pInfo->pPrivateDriverData);
4318 PVBOXWDDM_ALLOCATION pAllocation = vboxWddmGetAllocationFromHandle(pDevExt, pInfo->hAllocation);
4319 if (!pAllocation)
4320 {
4321 WARN(("invalid handle"));
4322 Status = STATUS_INVALID_PARAMETER;
4323 break;
4324 }
4325
4326#ifdef DEBUG
4327 Assert(!pAllocation->fAssumedDeletion);
4328#endif
4329 if (pRcInfo)
4330 {
4331 Assert(pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC);
4332
4333 if (pInfo->PrivateDriverDataSize != sizeof (VBOXWDDM_ALLOCINFO)
4334 || !pInfo->pPrivateDriverData)
4335 {
4336 WARN(("invalid data size"));
4337 Status = STATUS_INVALID_PARAMETER;
4338 break;
4339 }
4340
4341#ifdef VBOX_WITH_VIDEOHWACCEL
4342 PVBOXWDDM_ALLOCINFO pAllocInfo = (PVBOXWDDM_ALLOCINFO)pInfo->pPrivateDriverData;
4343
4344 if (pRcInfo->RcDesc.fFlags.Overlay)
4345 {
4346 /* we have queried host for some surface info, like pitch & size,
4347 * need to return it back to the UMD (User Mode Drive) */
4348 pAllocInfo->SurfDesc = pAllocation->AllocData.SurfDesc;
4349 /* success, just continue */
4350 }
4351#endif
4352 }
4353
4354 KIRQL OldIrql;
4355 PVBOXWDDM_OPENALLOCATION pOa;
4356 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
4357 pOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
4358 if (pOa)
4359 {
4360 ++pOa->cOpens;
4361 ++pAllocation->cOpens;
4362 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4363 }
4364 else
4365 {
4366 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4367 pOa = (PVBOXWDDM_OPENALLOCATION)vboxWddmMemAllocZero(sizeof (VBOXWDDM_OPENALLOCATION));
4368 if (!pOa)
4369 {
4370 WARN(("failed to allocation alloc info"));
4371 Status = STATUS_INSUFFICIENT_RESOURCES;
4372 break;
4373 }
4374
4375 pOa->hAllocation = pInfo->hAllocation;
4376 pOa->pAllocation = pAllocation;
4377 pOa->pDevice = pDevice;
4378 pOa->cOpens = 1;
4379
4380 PVBOXWDDM_OPENALLOCATION pConcurrentOa;
4381 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
4382 pConcurrentOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
4383 if (!pConcurrentOa)
4384 InsertHeadList(&pAllocation->OpenList, &pOa->ListEntry);
4385 else
4386 ++pConcurrentOa->cOpens;
4387 ++pAllocation->cOpens;
4388 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4389 if (pConcurrentOa)
4390 {
4391 vboxWddmMemFree(pOa);
4392 pOa = pConcurrentOa;
4393 }
4394 }
4395
4396 pInfo->hDeviceSpecificAllocation = pOa;
4397 }
4398
4399 if (Status != STATUS_SUCCESS)
4400 {
4401 for (UINT j = 0; j < i; ++j)
4402 {
4403 DXGK_OPENALLOCATIONINFO* pInfo2Free = &pOpenAllocation->pOpenAllocation[j];
4404 PVBOXWDDM_OPENALLOCATION pOa2Free = (PVBOXWDDM_OPENALLOCATION)pInfo2Free->hDeviceSpecificAllocation;
4405 VBoxWddmOaRelease(pOa2Free);
4406 }
4407 }
4408 }
4409 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4410
4411 return Status;
4412}
4413
4414NTSTATUS
4415APIENTRY
4416DxgkDdiCloseAllocation(
4417 CONST HANDLE hDevice,
4418 CONST DXGKARG_CLOSEALLOCATION* pCloseAllocation)
4419{
4420 RT_NOREF(hDevice);
4421 /* DxgkDdiCloseAllocation should be made pageable. */
4422 PAGED_CODE();
4423
4424 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4425
4426 vboxVDbgBreakFv();
4427
4428 for (UINT i = 0; i < pCloseAllocation->NumAllocations; ++i)
4429 {
4430 PVBOXWDDM_OPENALLOCATION pOa2Free = (PVBOXWDDM_OPENALLOCATION)pCloseAllocation->pOpenHandleList[i];
4431 PVBOXWDDM_ALLOCATION pAllocation = pOa2Free->pAllocation;
4432 Assert(pAllocation->cShRcRefs >= pOa2Free->cShRcRefs);
4433 pAllocation->cShRcRefs -= pOa2Free->cShRcRefs;
4434 VBoxWddmOaRelease(pOa2Free);
4435 }
4436
4437 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4438
4439 return STATUS_SUCCESS;
4440}
4441
4442#define VBOXVDMACMD_DMA_PRESENT_BLT_MINSIZE() (VBOXVDMACMD_SIZE(VBOXVDMACMD_DMA_PRESENT_BLT))
4443#define VBOXVDMACMD_DMA_PRESENT_BLT_SIZE(_c) (VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[_c]))
4444
4445DECLINLINE(BOOLEAN) vboxWddmPixFormatConversionSupported(D3DDDIFORMAT From, D3DDDIFORMAT To)
4446{
4447 Assert(From != D3DDDIFMT_UNKNOWN);
4448 Assert(To != D3DDDIFMT_UNKNOWN);
4449 Assert(From == To);
4450 return From == To;
4451}
4452
4453NTSTATUS
4454APIENTRY
4455DxgkDdiUpdateOverlay(
4456 CONST HANDLE hOverlay,
4457 CONST DXGKARG_UPDATEOVERLAY *pUpdateOverlay)
4458{
4459 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4460
4461 NTSTATUS Status = STATUS_SUCCESS;
4462
4463#ifdef VBOX_WITH_VIDEOHWACCEL
4464 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4465 AssertPtr(pOverlay);
4466 int rc = vboxVhwaHlpOverlayUpdate(pOverlay, &pUpdateOverlay->OverlayInfo);
4467 AssertRC(rc);
4468 if (RT_FAILURE(rc))
4469 Status = STATUS_UNSUCCESSFUL;
4470#else
4471 RT_NOREF(hOverlay, pUpdateOverlay);
4472#endif
4473
4474 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4475 return Status;
4476}
4477
4478NTSTATUS
4479APIENTRY
4480DxgkDdiFlipOverlay(
4481 CONST HANDLE hOverlay,
4482 CONST DXGKARG_FLIPOVERLAY *pFlipOverlay)
4483{
4484 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4485
4486 NTSTATUS Status = STATUS_SUCCESS;
4487
4488#ifdef VBOX_WITH_VIDEOHWACCEL
4489 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4490 AssertPtr(pOverlay);
4491 int rc = vboxVhwaHlpOverlayFlip(pOverlay, pFlipOverlay);
4492 AssertRC(rc);
4493 if (RT_FAILURE(rc))
4494 Status = STATUS_UNSUCCESSFUL;
4495#else
4496 RT_NOREF(hOverlay, pFlipOverlay);
4497#endif
4498
4499 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4500
4501 return Status;
4502}
4503
4504NTSTATUS
4505APIENTRY
4506DxgkDdiDestroyOverlay(
4507 CONST HANDLE hOverlay)
4508{
4509 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4510
4511 NTSTATUS Status = STATUS_SUCCESS;
4512
4513#ifdef VBOX_WITH_VIDEOHWACCEL
4514 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4515 AssertPtr(pOverlay);
4516 int rc = vboxVhwaHlpOverlayDestroy(pOverlay);
4517 AssertRC(rc);
4518 if (RT_SUCCESS(rc))
4519 vboxWddmMemFree(pOverlay);
4520 else
4521 Status = STATUS_UNSUCCESSFUL;
4522#else
4523 RT_NOREF(hOverlay);
4524#endif
4525
4526 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4527
4528 return Status;
4529}
4530
4531/**
4532 * DxgkDdiCreateContext
4533 */
4534NTSTATUS
4535APIENTRY
4536DxgkDdiCreateContext(
4537 CONST HANDLE hDevice,
4538 DXGKARG_CREATECONTEXT *pCreateContext)
4539{
4540 /* DxgkDdiCreateContext should be made pageable */
4541 PAGED_CODE();
4542
4543 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4544
4545 vboxVDbgBreakFv();
4546
4547 if (pCreateContext->NodeOrdinal >= VBOXWDDM_NUM_NODES)
4548 {
4549 WARN(("Invalid NodeOrdinal (%d), expected to be less that (%d)\n", pCreateContext->NodeOrdinal, VBOXWDDM_NUM_NODES));
4550 return STATUS_INVALID_PARAMETER;
4551 }
4552
4553 NTSTATUS Status = STATUS_SUCCESS;
4554 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4555 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4556 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)vboxWddmMemAllocZero(sizeof (VBOXWDDM_CONTEXT));
4557 Assert(pContext);
4558 if (pContext)
4559 {
4560 pContext->pDevice = pDevice;
4561 pContext->hContext = pCreateContext->hContext;
4562 pContext->EngineAffinity = pCreateContext->EngineAffinity;
4563 pContext->NodeOrdinal = pCreateContext->NodeOrdinal;
4564 vboxVideoCmCtxInitEmpty(&pContext->CmContext);
4565 if (pCreateContext->Flags.SystemContext || pCreateContext->PrivateDriverDataSize == 0)
4566 {
4567 Assert(pCreateContext->PrivateDriverDataSize == 0);
4568 Assert(!pCreateContext->pPrivateDriverData);
4569 Assert(pCreateContext->Flags.Value <= 2); /* 2 is a GDI context in Win7 */
4570 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_SYSTEM;
4571
4572 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VBOX)
4573 {
4574 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
4575 {
4576 vboxWddmDisplaySettingsCheckPos(pDevExt, i);
4577 }
4578 }
4579 Status = STATUS_SUCCESS;
4580 }
4581 else
4582 {
4583 Assert(pCreateContext->Flags.Value == 0);
4584 Assert(pCreateContext->PrivateDriverDataSize == sizeof (VBOXWDDM_CREATECONTEXT_INFO));
4585 Assert(pCreateContext->pPrivateDriverData);
4586 if (pCreateContext->PrivateDriverDataSize == sizeof (VBOXWDDM_CREATECONTEXT_INFO))
4587 {
4588 PVBOXWDDM_CREATECONTEXT_INFO pInfo = (PVBOXWDDM_CREATECONTEXT_INFO)pCreateContext->pPrivateDriverData;
4589 switch (pInfo->enmType)
4590 {
4591 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE:
4592 {
4593 pContext->enmType = pInfo->enmType;
4594 ASMAtomicIncU32(&pDevExt->cContextsDispIfResize);
4595 break;
4596 }
4597 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS:
4598 {
4599 pContext->enmType = pInfo->enmType;
4600 Status = vboxVideoCmCtxAdd(&pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext, (HANDLE)pInfo->u.vbox.hUmEvent, pInfo->u.vbox.u64UmInfo);
4601 if (!NT_SUCCESS(Status))
4602 {
4603 WARN(("vboxVideoCmCtxAdd failed, Status 0x%x", Status));
4604 }
4605 break;
4606 }
4607#ifdef VBOX_WITH_VMSVGA
4608 case VBOXWDDM_CONTEXT_TYPE_GA_3D:
4609 {
4610 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_GA_3D;
4611 Status = GaContextCreate(pDevExt->pGa, pInfo, pContext);
4612 break;
4613 }
4614#endif
4615#ifdef VBOX_WITH_VMSVGA3D_DX
4616 case VBOXWDDM_CONTEXT_TYPE_VMSVGA_D3D:
4617 {
4618 /* VMSVGA_D3D context type shares some code with GA_3D, because both work with VMSVGA GPU. */
4619 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_VMSVGA_D3D;
4620 Status = GaContextCreate(pDevExt->pGa, pInfo, pContext);
4621 break;
4622 }
4623#endif
4624 default:
4625 {
4626 WARN(("unsupported context type %d", pInfo->enmType));
4627 Status = STATUS_INVALID_PARAMETER;
4628 break;
4629 }
4630 }
4631 }
4632 }
4633
4634 if (Status == STATUS_SUCCESS)
4635 {
4636 pCreateContext->hContext = pContext;
4637 pCreateContext->ContextInfo.DmaBufferSize = VBOXWDDM_C_DMA_BUFFER_SIZE;
4638 pCreateContext->ContextInfo.DmaBufferSegmentSet = 0;
4639 pCreateContext->ContextInfo.DmaBufferPrivateDataSize = VBOXWDDM_C_DMA_PRIVATEDATA_SIZE;
4640 pCreateContext->ContextInfo.AllocationListSize = VBOXWDDM_C_ALLOC_LIST_SIZE;
4641 pCreateContext->ContextInfo.PatchLocationListSize = VBOXWDDM_C_PATH_LOCATION_LIST_SIZE;
4642 //#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN7)
4643 //# error port to Win7 DDI
4644 // //pCreateContext->ContextInfo.DmaBufferAllocationGroup = ???;
4645 //#endif // DXGKDDI_INTERFACE_VERSION
4646 }
4647 else
4648 vboxWddmMemFree(pContext);
4649 }
4650 else
4651 Status = STATUS_NO_MEMORY;
4652
4653 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4654
4655 return Status;
4656}
4657
4658NTSTATUS
4659APIENTRY
4660DxgkDdiDestroyContext(
4661 CONST HANDLE hContext)
4662{
4663 LOGF(("ENTER, hContext(0x%x)", hContext));
4664 vboxVDbgBreakFv();
4665 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
4666 PVBOXMP_DEVEXT pDevExt = pContext->pDevice->pAdapter;
4667 NTSTATUS Status = STATUS_SUCCESS;
4668
4669 switch(pContext->enmType)
4670 {
4671 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE:
4672 {
4673 uint32_t cContexts = ASMAtomicDecU32(&pDevExt->cContextsDispIfResize);
4674 Assert(cContexts < UINT32_MAX/2);
4675 if (!cContexts)
4676 {
4677 if (pDevExt->fDisableTargetUpdate)
4678 {
4679 pDevExt->fDisableTargetUpdate = FALSE;
4680 vboxWddmGhDisplayCheckSetInfoEx(pDevExt, true);
4681 }
4682 }
4683 break;
4684 }
4685 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS:
4686 {
4687 Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext);
4688 if (!NT_SUCCESS(Status))
4689 WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status));
4690
4691 Assert(pContext->CmContext.pSession == NULL);
4692 break;
4693 }
4694#ifdef VBOX_WITH_VMSVGA
4695 case VBOXWDDM_CONTEXT_TYPE_GA_3D:
4696 {
4697 Status = GaContextDestroy(pDevExt->pGa, pContext);
4698 break;
4699 }
4700#endif
4701#ifdef VBOX_WITH_VMSVGA3D_DX
4702 case VBOXWDDM_CONTEXT_TYPE_VMSVGA_D3D:
4703 {
4704 Status = GaContextDestroy(pDevExt->pGa, pContext);
4705 break;
4706 }
4707#endif
4708 default:
4709 break;
4710 }
4711
4712 Status = vboxVideoAMgrCtxDestroy(&pContext->AllocContext);
4713 if (NT_SUCCESS(Status))
4714 {
4715 Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->CmMgr, &pContext->CmContext);
4716 if (NT_SUCCESS(Status))
4717 vboxWddmMemFree(pContext);
4718 else
4719 WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status));
4720 }
4721 else
4722 WARN(("vboxVideoAMgrCtxDestroy failed, Status 0x%x", Status));
4723
4724 LOGF(("LEAVE, hContext(0x%x)", hContext));
4725
4726 return Status;
4727}
4728
4729NTSTATUS
4730APIENTRY
4731DxgkDdiLinkDevice(
4732 __in CONST PDEVICE_OBJECT PhysicalDeviceObject,
4733 __in CONST PVOID MiniportDeviceContext,
4734 __inout PLINKED_DEVICE LinkedDevice
4735 )
4736{
4737 RT_NOREF(PhysicalDeviceObject, MiniportDeviceContext, LinkedDevice);
4738 LOGF(("ENTER, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
4739 vboxVDbgBreakFv();
4740 AssertBreakpoint();
4741 LOGF(("LEAVE, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
4742 return STATUS_NOT_IMPLEMENTED;
4743}
4744
4745NTSTATUS
4746APIENTRY
4747DxgkDdiSetDisplayPrivateDriverFormat(
4748 CONST HANDLE hAdapter,
4749 /*CONST*/ DXGKARG_SETDISPLAYPRIVATEDRIVERFORMAT* pSetDisplayPrivateDriverFormat
4750 )
4751{
4752 RT_NOREF(hAdapter, pSetDisplayPrivateDriverFormat);
4753 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4754 vboxVDbgBreakFv();
4755 AssertBreakpoint();
4756 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4757 return STATUS_SUCCESS;
4758}
4759
4760NTSTATUS APIENTRY CALLBACK DxgkDdiRestartFromTimeout(IN_CONST_HANDLE hAdapter)
4761{
4762 RT_NOREF(hAdapter);
4763 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4764 vboxVDbgBreakFv();
4765 AssertBreakpoint();
4766 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4767 return STATUS_SUCCESS;
4768}
4769
4770static NTSTATUS APIENTRY DxgkDdiQueryVidPnHWCapability(
4771 __in const HANDLE hAdapter,
4772 __inout DXGKARG_QUERYVIDPNHWCAPABILITY *pVidPnHWCaps
4773 )
4774{
4775 RT_NOREF(hAdapter);
4776 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4777 vboxVDbgBreakF();
4778 pVidPnHWCaps->VidPnHWCaps.DriverRotation = 0;
4779 pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0;
4780 pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0;
4781 pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 0;
4782 pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0;
4783 pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0;
4784 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4785 return STATUS_SUCCESS;
4786}
4787
4788static NTSTATUS APIENTRY DxgkDdiPresentDisplayOnly(
4789 _In_ const HANDLE hAdapter,
4790 _In_ const DXGKARG_PRESENT_DISPLAYONLY *pPresentDisplayOnly
4791 )
4792{
4793 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4794 vboxVDbgBreakFv();
4795
4796 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4797#ifdef VBOX_WITH_VMSVGA
4798 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4799 {
4800 return GaDxgkDdiPresentDisplayOnly(hAdapter, pPresentDisplayOnly);
4801 }
4802#endif
4803 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pPresentDisplayOnly->VidPnSourceId];
4804 Assert(pSource->AllocData.Addr.SegmentId == 1);
4805 VBOXWDDM_ALLOC_DATA SrcAllocData;
4806 SrcAllocData.SurfDesc.width = pPresentDisplayOnly->Pitch * pPresentDisplayOnly->BytesPerPixel;
4807 SrcAllocData.SurfDesc.height = ~0UL;
4808 switch (pPresentDisplayOnly->BytesPerPixel)
4809 {
4810 case 4:
4811 SrcAllocData.SurfDesc.format = D3DDDIFMT_A8R8G8B8;
4812 break;
4813 case 3:
4814 SrcAllocData.SurfDesc.format = D3DDDIFMT_R8G8B8;
4815 break;
4816 case 2:
4817 SrcAllocData.SurfDesc.format = D3DDDIFMT_R5G6B5;
4818 break;
4819 case 1:
4820 SrcAllocData.SurfDesc.format = D3DDDIFMT_P8;
4821 break;
4822 default:
4823 WARN(("Unknown format"));
4824 SrcAllocData.SurfDesc.format = D3DDDIFMT_UNKNOWN;
4825 break;
4826 }
4827 SrcAllocData.SurfDesc.bpp = pPresentDisplayOnly->BytesPerPixel >> 3;
4828 SrcAllocData.SurfDesc.pitch = pPresentDisplayOnly->Pitch;
4829 SrcAllocData.SurfDesc.depth = 1;
4830 SrcAllocData.SurfDesc.slicePitch = pPresentDisplayOnly->Pitch;
4831 SrcAllocData.SurfDesc.cbSize = ~0UL;
4832 SrcAllocData.Addr.SegmentId = 0;
4833 SrcAllocData.Addr.pvMem = pPresentDisplayOnly->pSource;
4834 SrcAllocData.hostID = 0;
4835
4836 RECT UpdateRect;
4837 RT_ZERO(UpdateRect);
4838 BOOLEAN bUpdateRectInited = FALSE;
4839
4840 for (UINT i = 0; i < pPresentDisplayOnly->NumMoves; ++i)
4841 {
4842 if (!bUpdateRectInited)
4843 {
4844 UpdateRect = pPresentDisplayOnly->pMoves[i].DestRect;
4845 bUpdateRectInited = TRUE;
4846 }
4847 else
4848 vboxWddmRectUnite(&UpdateRect, &pPresentDisplayOnly->pMoves[i].DestRect);
4849 vboxVdmaGgDmaBltPerform(pDevExt, &SrcAllocData, &pPresentDisplayOnly->pMoves[i].DestRect, &pSource->AllocData, &pPresentDisplayOnly->pMoves[i].DestRect);
4850 }
4851
4852 for (UINT i = 0; i < pPresentDisplayOnly->NumDirtyRects; ++i)
4853 {
4854 RECT *pDirtyRect = &pPresentDisplayOnly->pDirtyRect[i];
4855
4856 if (pDirtyRect->left >= pDirtyRect->right || pDirtyRect->top >= pDirtyRect->bottom)
4857 {
4858 WARN(("Wrong dirty rect (%d, %d)-(%d, %d)",
4859 pDirtyRect->left, pDirtyRect->top, pDirtyRect->right, pDirtyRect->bottom));
4860 continue;
4861 }
4862
4863 vboxVdmaGgDmaBltPerform(pDevExt, &SrcAllocData, pDirtyRect, &pSource->AllocData, pDirtyRect);
4864
4865 if (!bUpdateRectInited)
4866 {
4867 UpdateRect = *pDirtyRect;
4868 bUpdateRectInited = TRUE;
4869 }
4870 else
4871 vboxWddmRectUnite(&UpdateRect, pDirtyRect);
4872 }
4873
4874 if (bUpdateRectInited && pSource->bVisible)
4875 {
4876 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UpdateRect);
4877 }
4878
4879 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4880 return STATUS_SUCCESS;
4881}
4882
4883static NTSTATUS DxgkDdiStopDeviceAndReleasePostDisplayOwnership(
4884 _In_ PVOID MiniportDeviceContext,
4885 _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
4886 _Out_ PDXGK_DISPLAY_INFORMATION DisplayInfo
4887)
4888{
4889 RT_NOREF(MiniportDeviceContext, TargetId, DisplayInfo);
4890 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4891 vboxVDbgBreakFv();
4892 AssertBreakpoint();
4893 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4894 return STATUS_NOT_SUPPORTED;
4895}
4896
4897static NTSTATUS DxgkDdiSystemDisplayEnable(
4898 _In_ PVOID MiniportDeviceContext,
4899 _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
4900 _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
4901 _Out_ UINT *Width,
4902 _Out_ UINT *Height,
4903 _Out_ D3DDDIFORMAT *ColorFormat
4904 )
4905{
4906 RT_NOREF(MiniportDeviceContext, TargetId, Flags, Width, Height, ColorFormat);
4907 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4908 vboxVDbgBreakFv();
4909 AssertBreakpoint();
4910 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4911 return STATUS_NOT_SUPPORTED;
4912}
4913
4914static VOID DxgkDdiSystemDisplayWrite(
4915 _In_ PVOID MiniportDeviceContext,
4916 _In_ PVOID Source,
4917 _In_ UINT SourceWidth,
4918 _In_ UINT SourceHeight,
4919 _In_ UINT SourceStride,
4920 _In_ UINT PositionX,
4921 _In_ UINT PositionY
4922)
4923{
4924 RT_NOREF(MiniportDeviceContext, Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY);
4925 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4926 vboxVDbgBreakFv();
4927 AssertBreakpoint();
4928 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4929}
4930
4931static NTSTATUS DxgkDdiGetChildContainerId(
4932 _In_ PVOID MiniportDeviceContext,
4933 _In_ ULONG ChildUid,
4934 _Inout_ PDXGK_CHILD_CONTAINER_ID ContainerId
4935)
4936{
4937 RT_NOREF(MiniportDeviceContext, ChildUid, ContainerId);
4938 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4939 vboxVDbgBreakFv();
4940 AssertBreakpoint();
4941 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4942 return STATUS_SUCCESS;
4943}
4944
4945static NTSTATUS APIENTRY DxgkDdiSetPowerComponentFState(
4946 _In_ const HANDLE DriverContext,
4947 UINT ComponentIndex,
4948 UINT FState
4949)
4950{
4951 RT_NOREF(DriverContext, ComponentIndex, FState);
4952 LOGF(("ENTER, DriverContext(0x%x)", DriverContext));
4953 vboxVDbgBreakFv();
4954 AssertBreakpoint();
4955 LOGF(("LEAVE, DriverContext(0x%x)", DriverContext));
4956 return STATUS_SUCCESS;
4957}
4958
4959static NTSTATUS APIENTRY DxgkDdiPowerRuntimeControlRequest(
4960 _In_ const HANDLE DriverContext,
4961 _In_ LPCGUID PowerControlCode,
4962 _In_opt_ PVOID InBuffer,
4963 _In_ SIZE_T InBufferSize,
4964 _Out_opt_ PVOID OutBuffer,
4965 _In_ SIZE_T OutBufferSize,
4966 _Out_opt_ PSIZE_T BytesReturned
4967)
4968{
4969 RT_NOREF(DriverContext, PowerControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned);
4970 LOGF(("ENTER, DriverContext(0x%x)", DriverContext));
4971 vboxVDbgBreakFv();
4972 AssertBreakpoint();
4973 LOGF(("LEAVE, DriverContext(0x%x)", DriverContext));
4974 return STATUS_SUCCESS;
4975}
4976
4977static NTSTATUS DxgkDdiNotifySurpriseRemoval(
4978 _In_ PVOID MiniportDeviceContext,
4979 _In_ DXGK_SURPRISE_REMOVAL_TYPE RemovalType
4980 )
4981{
4982 RT_NOREF(MiniportDeviceContext, RemovalType);
4983 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4984 vboxVDbgBreakFv();
4985 AssertBreakpoint();
4986 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4987 return STATUS_SUCCESS;
4988}
4989
4990static BOOLEAN DxgkDdiInterruptRoutine(const PVOID MiniportDeviceContext,
4991 ULONG MessageNumber)
4992{
4993#ifdef VBOX_WITH_VMSVGA
4994 BOOLEAN const fVMSVGA = GaDxgkDdiInterruptRoutine(MiniportDeviceContext, MessageNumber);
4995#else
4996 BOOLEAN const fVMSVGA = FALSE;
4997#endif
4998
4999 BOOLEAN const fHGSMI = DxgkDdiInterruptRoutineLegacy(MiniportDeviceContext, MessageNumber);
5000 return fVMSVGA || fHGSMI;
5001}
5002
5003static VOID DxgkDdiDpcRoutine(const PVOID MiniportDeviceContext)
5004{
5005 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
5006
5007#ifdef VBOX_WITH_VMSVGA
5008 GaDxgkDdiDpcRoutine(MiniportDeviceContext);
5009#endif
5010 DxgkDdiDpcRoutineLegacy(MiniportDeviceContext);
5011
5012 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
5013}
5014
5015static NTSTATUS vboxWddmInitDisplayOnlyDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
5016{
5017 KMDDOD_INITIALIZATION_DATA DriverInitializationData = {'\0'};
5018
5019 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_WIN8;
5020
5021 DriverInitializationData.DxgkDdiAddDevice = DxgkDdiAddDevice;
5022 DriverInitializationData.DxgkDdiStartDevice = DxgkDdiStartDevice;
5023 DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice;
5024 DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice;
5025 DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest;
5026 DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine;
5027 DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine;
5028 DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations;
5029 DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus;
5030 DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor;
5031 DriverInitializationData.DxgkDdiSetPowerState = DxgkDdiSetPowerState;
5032 DriverInitializationData.DxgkDdiNotifyAcpiEvent = DxgkDdiNotifyAcpiEvent;
5033 DriverInitializationData.DxgkDdiResetDevice = DxgkDdiResetDevice;
5034 DriverInitializationData.DxgkDdiUnload = DxgkDdiUnload;
5035 DriverInitializationData.DxgkDdiQueryInterface = DxgkDdiQueryInterface;
5036 DriverInitializationData.DxgkDdiControlEtwLogging = DxgkDdiControlEtwLogging;
5037 DriverInitializationData.DxgkDdiQueryAdapterInfo = DxgkDdiQueryAdapterInfo;
5038 DriverInitializationData.DxgkDdiSetPalette = DxgkDdiSetPalette;
5039 DriverInitializationData.DxgkDdiSetPointerPosition = DxgkDdiSetPointerPosition;
5040 DriverInitializationData.DxgkDdiSetPointerShape = DxgkDdiSetPointerShape;
5041 DriverInitializationData.DxgkDdiEscape = DxgkDdiEscape;
5042 DriverInitializationData.DxgkDdiCollectDbgInfo = DxgkDdiCollectDbgInfo;
5043 DriverInitializationData.DxgkDdiIsSupportedVidPn = DxgkDdiIsSupportedVidPn;
5044 DriverInitializationData.DxgkDdiRecommendFunctionalVidPn = DxgkDdiRecommendFunctionalVidPn;
5045 DriverInitializationData.DxgkDdiEnumVidPnCofuncModality = DxgkDdiEnumVidPnCofuncModality;
5046 DriverInitializationData.DxgkDdiSetVidPnSourceVisibility = DxgkDdiSetVidPnSourceVisibility;
5047 DriverInitializationData.DxgkDdiCommitVidPn = DxgkDdiCommitVidPn;
5048 DriverInitializationData.DxgkDdiUpdateActiveVidPnPresentPath = DxgkDdiUpdateActiveVidPnPresentPath;
5049 DriverInitializationData.DxgkDdiRecommendMonitorModes = DxgkDdiRecommendMonitorModes;
5050 DriverInitializationData.DxgkDdiQueryVidPnHWCapability = DxgkDdiQueryVidPnHWCapability;
5051 DriverInitializationData.DxgkDdiPresentDisplayOnly = DxgkDdiPresentDisplayOnly;
5052 DriverInitializationData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = DxgkDdiStopDeviceAndReleasePostDisplayOwnership;
5053 DriverInitializationData.DxgkDdiSystemDisplayEnable = DxgkDdiSystemDisplayEnable;
5054 DriverInitializationData.DxgkDdiSystemDisplayWrite = DxgkDdiSystemDisplayWrite;
5055// DriverInitializationData.DxgkDdiGetChildContainerId = DxgkDdiGetChildContainerId;
5056// DriverInitializationData.DxgkDdiSetPowerComponentFState = DxgkDdiSetPowerComponentFState;
5057// DriverInitializationData.DxgkDdiPowerRuntimeControlRequest = DxgkDdiPowerRuntimeControlRequest;
5058// DriverInitializationData.DxgkDdiNotifySurpriseRemoval = DxgkDdiNotifySurpriseRemoval;
5059
5060 /* Display-only driver is not required to report VSYNC.
5061 * The Microsoft KMDOD driver sample does not implement DxgkDdiControlInterrupt and DxgkDdiGetScanLine.
5062 * The functions must be either both implemented or none implemented.
5063 * Windows 10 10586 guests had problems with VSYNC in display-only driver (#8228).
5064 * Therefore the driver does not implement DxgkDdiControlInterrupt and DxgkDdiGetScanLine.
5065 */
5066
5067 NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject,
5068 pRegistryPath,
5069 &DriverInitializationData);
5070 if (!NT_SUCCESS(Status))
5071 {
5072 WARN(("DxgkInitializeDisplayOnlyDriver failed! Status 0x%x", Status));
5073 }
5074 return Status;
5075}
5076
5077static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath, VBOXVIDEO_HWTYPE enmHwType)
5078{
5079 DRIVER_INITIALIZATION_DATA DriverInitializationData = {'\0'};
5080
5081 // Fill in the DriverInitializationData structure and call DxgkInitialize()
5082 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
5083 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_WIN8;
5084 else
5085 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_VISTA_SP1;
5086
5087 DriverInitializationData.DxgkDdiAddDevice = DxgkDdiAddDevice;
5088 DriverInitializationData.DxgkDdiStartDevice = DxgkDdiStartDevice;
5089 DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice;
5090 DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice;
5091 DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest;
5092 DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine;
5093 DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine;
5094
5095#ifdef VBOX_WITH_VMSVGA
5096 if (enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
5097 {
5098 DriverInitializationData.DxgkDdiPatch = GaDxgkDdiPatch;
5099 DriverInitializationData.DxgkDdiSubmitCommand = GaDxgkDdiSubmitCommand;
5100 DriverInitializationData.DxgkDdiPreemptCommand = GaDxgkDdiPreemptCommand;
5101 DriverInitializationData.DxgkDdiBuildPagingBuffer = GaDxgkDdiBuildPagingBuffer;
5102 DriverInitializationData.DxgkDdiQueryCurrentFence = GaDxgkDdiQueryCurrentFence;
5103 DriverInitializationData.DxgkDdiRender = GaDxgkDdiRender;
5104 DriverInitializationData.DxgkDdiPresent = SvgaDxgkDdiPresent;
5105 }
5106 else
5107#endif
5108 {
5109 RT_NOREF(enmHwType);
5110
5111 DriverInitializationData.DxgkDdiPatch = DxgkDdiPatchLegacy;
5112 DriverInitializationData.DxgkDdiSubmitCommand = DxgkDdiSubmitCommandLegacy;
5113 DriverInitializationData.DxgkDdiPreemptCommand = DxgkDdiPreemptCommandLegacy;
5114 DriverInitializationData.DxgkDdiBuildPagingBuffer = DxgkDdiBuildPagingBufferLegacy;
5115 DriverInitializationData.DxgkDdiQueryCurrentFence = DxgkDdiQueryCurrentFenceLegacy;
5116 DriverInitializationData.DxgkDdiRender = DxgkDdiRenderLegacy;
5117 DriverInitializationData.DxgkDdiPresent = DxgkDdiPresentLegacy;
5118 }
5119
5120 DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations;
5121 DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus;
5122 DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor;
5123 DriverInitializationData.DxgkDdiSetPowerState = DxgkDdiSetPowerState;
5124 DriverInitializationData.DxgkDdiNotifyAcpiEvent = DxgkDdiNotifyAcpiEvent;
5125 DriverInitializationData.DxgkDdiResetDevice = DxgkDdiResetDevice;
5126 DriverInitializationData.DxgkDdiUnload = DxgkDdiUnload;
5127 DriverInitializationData.DxgkDdiQueryInterface = DxgkDdiQueryInterface;
5128 DriverInitializationData.DxgkDdiControlEtwLogging = DxgkDdiControlEtwLogging;
5129
5130 DriverInitializationData.DxgkDdiQueryAdapterInfo = DxgkDdiQueryAdapterInfo;
5131 DriverInitializationData.DxgkDdiCreateDevice = DxgkDdiCreateDevice;
5132 DriverInitializationData.DxgkDdiCreateAllocation = DxgkDdiCreateAllocation;
5133 DriverInitializationData.DxgkDdiDestroyAllocation = DxgkDdiDestroyAllocation;
5134 DriverInitializationData.DxgkDdiDescribeAllocation = DxgkDdiDescribeAllocation;
5135 DriverInitializationData.DxgkDdiGetStandardAllocationDriverData = DxgkDdiGetStandardAllocationDriverData;
5136 DriverInitializationData.DxgkDdiAcquireSwizzlingRange = DxgkDdiAcquireSwizzlingRange;
5137 DriverInitializationData.DxgkDdiReleaseSwizzlingRange = DxgkDdiReleaseSwizzlingRange;
5138
5139 DriverInitializationData.DxgkDdiSetPalette = DxgkDdiSetPalette;
5140 DriverInitializationData.DxgkDdiSetPointerPosition = DxgkDdiSetPointerPosition;
5141 DriverInitializationData.DxgkDdiSetPointerShape = DxgkDdiSetPointerShape;
5142 DriverInitializationData.DxgkDdiResetFromTimeout = DxgkDdiResetFromTimeout;
5143 DriverInitializationData.DxgkDdiRestartFromTimeout = DxgkDdiRestartFromTimeout;
5144 DriverInitializationData.DxgkDdiEscape = DxgkDdiEscape;
5145 DriverInitializationData.DxgkDdiCollectDbgInfo = DxgkDdiCollectDbgInfo;
5146 DriverInitializationData.DxgkDdiIsSupportedVidPn = DxgkDdiIsSupportedVidPn;
5147 DriverInitializationData.DxgkDdiRecommendFunctionalVidPn = DxgkDdiRecommendFunctionalVidPn;
5148 DriverInitializationData.DxgkDdiEnumVidPnCofuncModality = DxgkDdiEnumVidPnCofuncModality;
5149 DriverInitializationData.DxgkDdiSetVidPnSourceAddress = DxgkDdiSetVidPnSourceAddress;
5150 DriverInitializationData.DxgkDdiSetVidPnSourceVisibility = DxgkDdiSetVidPnSourceVisibility;
5151 DriverInitializationData.DxgkDdiCommitVidPn = DxgkDdiCommitVidPn;
5152 DriverInitializationData.DxgkDdiUpdateActiveVidPnPresentPath = DxgkDdiUpdateActiveVidPnPresentPath;
5153 DriverInitializationData.DxgkDdiRecommendMonitorModes = DxgkDdiRecommendMonitorModes;
5154 DriverInitializationData.DxgkDdiRecommendVidPnTopology = DxgkDdiRecommendVidPnTopology;
5155 DriverInitializationData.DxgkDdiGetScanLine = DxgkDdiGetScanLine;
5156 DriverInitializationData.DxgkDdiStopCapture = DxgkDdiStopCapture;
5157 DriverInitializationData.DxgkDdiControlInterrupt = DxgkDdiControlInterrupt;
5158 DriverInitializationData.DxgkDdiCreateOverlay = DxgkDdiCreateOverlay;
5159
5160 DriverInitializationData.DxgkDdiDestroyDevice = DxgkDdiDestroyDevice;
5161 DriverInitializationData.DxgkDdiOpenAllocation = DxgkDdiOpenAllocation;
5162 DriverInitializationData.DxgkDdiCloseAllocation = DxgkDdiCloseAllocation;
5163
5164 DriverInitializationData.DxgkDdiUpdateOverlay = DxgkDdiUpdateOverlay;
5165 DriverInitializationData.DxgkDdiFlipOverlay = DxgkDdiFlipOverlay;
5166 DriverInitializationData.DxgkDdiDestroyOverlay = DxgkDdiDestroyOverlay;
5167
5168 DriverInitializationData.DxgkDdiCreateContext = DxgkDdiCreateContext;
5169 DriverInitializationData.DxgkDdiDestroyContext = DxgkDdiDestroyContext;
5170
5171 DriverInitializationData.DxgkDdiLinkDevice = NULL; //DxgkDdiLinkDevice;
5172 DriverInitializationData.DxgkDdiSetDisplayPrivateDriverFormat = DxgkDdiSetDisplayPrivateDriverFormat;
5173
5174 if (DriverInitializationData.Version >= DXGKDDI_INTERFACE_VERSION_WIN7)
5175 {
5176 DriverInitializationData.DxgkDdiQueryVidPnHWCapability = DxgkDdiQueryVidPnHWCapability;
5177 }
5178
5179 NTSTATUS Status = DxgkInitialize(pDriverObject,
5180 pRegistryPath,
5181 &DriverInitializationData);
5182 if (!NT_SUCCESS(Status))
5183 {
5184 WARN(("DxgkInitialize failed! Status 0x%x", Status));
5185 }
5186 return Status;
5187}
5188
5189NTSTATUS
5190DriverEntry(
5191 IN PDRIVER_OBJECT DriverObject,
5192 IN PUNICODE_STRING RegistryPath
5193 )
5194{
5195 PAGED_CODE();
5196
5197 vboxVDbgBreakFv();
5198
5199 int irc = RTR0Init(0);
5200 if (RT_FAILURE(irc))
5201 {
5202 RTLogBackdoorPrintf("VBoxWddm: RTR0Init failed: %Rrc!\n", irc);
5203 return STATUS_UNSUCCESSFUL;
5204 }
5205
5206#if 0//def DEBUG_misha
5207 RTLogGroupSettings(0, "+default.e.l.f.l2.l3");
5208#endif
5209
5210#ifdef DEBUG
5211#define VBOXWDDM_BUILD_TYPE "dbg"
5212#else
5213#define VBOXWDDM_BUILD_TYPE "rel"
5214#endif
5215
5216 LOGREL(("VBox WDDM Driver for Windows %s version %d.%d.%dr%d %s, %d bit; Built %s %s",
5217 VBoxQueryWinVersion(NULL) >= WINVERSION_8 ? "8+" : "Vista and 7",
5218 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
5219 VBOXWDDM_BUILD_TYPE,
5220 (sizeof (void*) << 3), __DATE__, __TIME__));
5221
5222 if ( !ARGUMENT_PRESENT(DriverObject)
5223 || !ARGUMENT_PRESENT(RegistryPath))
5224 return STATUS_INVALID_PARAMETER;
5225
5226 vboxWddmDrvCfgInit(RegistryPath);
5227
5228 ULONG major, minor, build;
5229 BOOLEAN fCheckedBuild = PsGetVersion(&major, &minor, &build, NULL); NOREF(fCheckedBuild);
5230 BOOLEAN f3DRequired = FALSE;
5231
5232 LOGREL(("OsVersion(%d, %d, %d)", major, minor, build));
5233
5234 NTSTATUS Status = STATUS_SUCCESS;
5235 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
5236 int rc = VbglR0InitClient();
5237 if (RT_SUCCESS(rc))
5238 {
5239 /* Check whether 3D is required by the guest. */
5240 if (major > 6)
5241 {
5242 /* Windows 10 and newer. */
5243 f3DRequired = TRUE;
5244 }
5245 else if (major == 6)
5246 {
5247 if (minor >= 2)
5248 {
5249 /* Windows 8, 8.1 and 10 preview. */
5250 f3DRequired = TRUE;
5251 }
5252 else
5253 {
5254 f3DRequired = FALSE;
5255 }
5256 }
5257 else
5258 {
5259 WARN(("Unsupported OLDER win version, ignore and assume 3D is NOT required"));
5260 f3DRequired = FALSE;
5261 }
5262
5263 LOG(("3D is %srequired!", f3DRequired? "": "NOT "));
5264
5265 /* Check whether 3D is provided by the host. */
5266 VBOXVIDEO_HWTYPE enmHwType = VBOXVIDEO_HWTYPE_VBOX;
5267 BOOL f3DSupported = FALSE;
5268
5269 if (VBoxVGACfgAvailable())
5270 {
5271 /* New configuration query interface is available. */
5272 uint32_t u32;
5273 if (VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VERSION, &u32, 0))
5274 {
5275 LOGREL(("WDDM: VGA configuration version %d", u32));
5276 }
5277
5278 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_3D, &u32, 0);
5279 f3DSupported = RT_BOOL(u32);
5280
5281 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VMSVGA, &u32, 0);
5282 if (u32)
5283 {
5284 enmHwType = VBOXVIDEO_HWTYPE_VMSVGA;
5285 }
5286 LOGREL(("WDDM: VGA configuration: 3D %d, hardware type %d", f3DSupported, enmHwType));
5287 }
5288
5289 if (enmHwType == VBOXVIDEO_HWTYPE_VBOX)
5290 {
5291 /* No 3D for legacy adapter. */
5292 f3DSupported = FALSE;
5293 }
5294 else if (enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
5295 {
5296 /* Nothing. */
5297 }
5298 else
5299 {
5300 /* No supported hardware, fallback to VBox 2D only. */
5301 enmHwType = VBOXVIDEO_HWTYPE_VBOX;
5302 f3DSupported = FALSE;
5303 }
5304
5305 LOGREL(("WDDM: 3D is %ssupported, hardware type %d", f3DSupported? "": "not ", enmHwType));
5306
5307 if (NT_SUCCESS(Status))
5308 {
5309 if (!f3DSupported)
5310 {
5311 /* No 3D support by the host. */
5312 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
5313 {
5314 /* Use display only driver for Win8+. */
5315 g_VBoxDisplayOnly = 1;
5316
5317 /* Black list some builds. */
5318 if (major == 6 && minor == 4 && build == 9841)
5319 {
5320 /* W10 Technical preview crashes with display-only driver. */
5321 LOGREL(("3D is NOT supported by the host, fallback to the system video driver."));
5322 Status = STATUS_UNSUCCESSFUL;
5323 }
5324 else
5325 {
5326 LOGREL(("3D is NOT supported by the host, falling back to display-only mode.."));
5327 }
5328 }
5329 else
5330 {
5331 if (f3DRequired)
5332 {
5333 LOGREL(("3D is NOT supported by the host, but is required for the current guest version using this driver.."));
5334 Status = STATUS_UNSUCCESSFUL;
5335 }
5336 else
5337 LOGREL(("3D is NOT supported by the host, but is NOT required for the current guest version using this driver, continuing with Disabled 3D.."));
5338 }
5339 }
5340 }
5341
5342 if (NT_SUCCESS(Status))
5343 {
5344 if (g_VBoxDisplayOnly)
5345 {
5346 Status = vboxWddmInitDisplayOnlyDriver(DriverObject, RegistryPath);
5347 }
5348 else
5349 {
5350 Status = vboxWddmInitFullGraphicsDriver(DriverObject, RegistryPath, enmHwType);
5351 }
5352
5353 if (NT_SUCCESS(Status))
5354 {
5355 /*
5356 * Successfully initialized the driver.
5357 */
5358 return Status;
5359 }
5360
5361 /*
5362 * Cleanup on failure.
5363 */
5364 }
5365 else
5366 LOGREL(("Aborting the video driver load due to 3D support missing"));
5367
5368 VbglR0TerminateClient();
5369 }
5370 else
5371 {
5372 WARN(("VbglR0InitClient failed, rc(%d)", rc));
5373 Status = STATUS_UNSUCCESSFUL;
5374 }
5375
5376 AssertRelease(!NT_SUCCESS(Status));
5377
5378 PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
5379 if (pLogger)
5380 {
5381 RTLogDestroy(pLogger);
5382 }
5383 pLogger = RTLogSetDefaultInstance(NULL);
5384 if (pLogger)
5385 {
5386 RTLogDestroy(pLogger);
5387 }
5388
5389 return Status;
5390}
Note: See TracBrowser for help on using the repository browser.

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