VirtualBox

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

Last change on this file since 104836 was 104836, checked in by vboxsync, 11 months ago

Additions/Graphics: Implemented missing support for reporting the mouse cursor positions to the host within the XPDM + WDDM mini port drivers. bugref:10650

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