VirtualBox

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

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

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 194.4 KB
Line 
1/* $Id: VBoxMPWddm.cpp 98103 2023-01-17 14:15:46Z 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 always 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<pPointerAttributes->Height; ++y)
2902 {
2903 for (x=0, bit=7; x<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<pPointerAttributes->Height; ++y)
2920 {
2921 memcpy(pDst+y*dstBytesPerLine, pSrc+y*pSetPointerShape->Pitch, dstBytesPerLine);
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
3133NTSTATUS
3134APIENTRY
3135DxgkDdiSetPointerPosition(
3136 CONST HANDLE hAdapter,
3137 CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
3138{
3139// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3140
3141 vboxVDbgBreakFv();
3142
3143 /* mouse integration is ON */
3144 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3145 PVBOXWDDM_POINTER_INFO pPointerInfo = &pDevExt->aSources[pSetPointerPosition->VidPnSourceId].PointerInfo;
3146 PVBOXWDDM_GLOBAL_POINTER_INFO pGlobalPointerInfo = &pDevExt->PointerInfo;
3147 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = &pPointerInfo->Attributes.data;
3148 BOOLEAN fScreenVisState = !!(pPointerAttributes->Enable & VBOX_MOUSE_POINTER_VISIBLE);
3149 BOOLEAN fVisStateChanged = FALSE;
3150 BOOLEAN fScreenChanged = pGlobalPointerInfo->iLastReportedScreen != pSetPointerPosition->VidPnSourceId;
3151
3152 if (pSetPointerPosition->Flags.Visible)
3153 {
3154 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_VISIBLE;
3155 if (!fScreenVisState)
3156 {
3157 fVisStateChanged = TRUE;
3158 }
3159 }
3160 else
3161 {
3162 pPointerAttributes->Enable &= ~VBOX_MOUSE_POINTER_VISIBLE;
3163 if (fScreenVisState)
3164 {
3165 fVisStateChanged = TRUE;
3166 }
3167 }
3168
3169 pGlobalPointerInfo->iLastReportedScreen = pSetPointerPosition->VidPnSourceId;
3170
3171 if ((fVisStateChanged || fScreenChanged) && VBoxQueryHostWantsAbsolute())
3172 {
3173 if (fScreenChanged)
3174 {
3175 BOOLEAN bResult = vboxWddmUpdatePointerShape(pDevExt, &pPointerInfo->Attributes.data, VBOXWDDM_POINTER_ATTRIBUTES_SIZE);
3176 if (!bResult)
3177 {
3178 vboxWddmHostPointerEnable(pDevExt, FALSE);
3179 }
3180 }
3181
3182 // Always update the visibility as requested. Tell the host to use the guest's pointer.
3183 vboxWddmHostPointerEnable(pDevExt, pSetPointerPosition->Flags.Visible);
3184 }
3185
3186// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3187
3188 return STATUS_SUCCESS;
3189}
3190
3191NTSTATUS
3192APIENTRY
3193DxgkDdiSetPointerShape(
3194 CONST HANDLE hAdapter,
3195 CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
3196{
3197// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3198
3199 vboxVDbgBreakFv();
3200
3201 NTSTATUS Status = STATUS_NOT_SUPPORTED;
3202
3203 if (VBoxQueryHostWantsAbsolute())
3204 {
3205 /* mouse integration is ON */
3206 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3207 PVBOXWDDM_POINTER_INFO pPointerInfo = &pDevExt->aSources[pSetPointerShape->VidPnSourceId].PointerInfo;
3208 bool const fDwordAlignScanlines = pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VBOX;
3209 /** @todo to avoid extra data copy and extra heap allocation,
3210 * need to maintain the pre-allocated HGSMI buffer and convert the data directly to it */
3211 if (vboxVddmPointerShapeToAttributes(pSetPointerShape, pPointerInfo, fDwordAlignScanlines))
3212 {
3213 pDevExt->PointerInfo.iLastReportedScreen = pSetPointerShape->VidPnSourceId;
3214 if (vboxWddmUpdatePointerShape(pDevExt, &pPointerInfo->Attributes.data, VBOXWDDM_POINTER_ATTRIBUTES_SIZE))
3215 Status = STATUS_SUCCESS;
3216 else
3217 {
3218 // tell the host to use the guest's pointer
3219 vboxWddmHostPointerEnable(pDevExt, FALSE);
3220 }
3221 }
3222 }
3223
3224// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3225
3226 return Status;
3227}
3228
3229NTSTATUS
3230APIENTRY CALLBACK
3231DxgkDdiResetFromTimeout(
3232 CONST HANDLE hAdapter)
3233{
3234 RT_NOREF(hAdapter);
3235 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3236
3237 AssertBreakpoint();
3238 /** @todo fixme: implement */
3239
3240 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3241
3242 return STATUS_SUCCESS;
3243}
3244
3245
3246/* the lpRgnData->Buffer comes to us as RECT
3247 * to avoid extra memcpy we cast it to PRTRECT assuming
3248 * they are identical */
3249AssertCompile(sizeof(RECT) == sizeof(RTRECT));
3250AssertCompile(RT_OFFSETOF(RECT, left) == RT_OFFSETOF(RTRECT, xLeft));
3251AssertCompile(RT_OFFSETOF(RECT, bottom) == RT_OFFSETOF(RTRECT, yBottom));
3252AssertCompile(RT_OFFSETOF(RECT, right) == RT_OFFSETOF(RTRECT, xRight));
3253AssertCompile(RT_OFFSETOF(RECT, top) == RT_OFFSETOF(RTRECT, yTop));
3254
3255NTSTATUS
3256APIENTRY
3257DxgkDdiEscape(
3258 CONST HANDLE hAdapter,
3259 CONST DXGKARG_ESCAPE* pEscape)
3260{
3261 PAGED_CODE();
3262
3263// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3264
3265 NTSTATUS Status = STATUS_NOT_SUPPORTED;
3266 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3267 Assert(pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE));
3268 if (pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE))
3269 {
3270 PVBOXDISPIFESCAPE pEscapeHdr = (PVBOXDISPIFESCAPE)pEscape->pPrivateDriverData;
3271 switch (pEscapeHdr->escapeCode)
3272 {
3273 case VBOXESC_SETVISIBLEREGION:
3274 {
3275#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3276 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3277 if (!pContext)
3278 {
3279 WARN(("VBOXESC_SETVISIBLEREGION no context supplied!"));
3280 Status = STATUS_INVALID_PARAMETER;
3281 break;
3282 }
3283
3284 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS)
3285 {
3286 WARN(("VBOXESC_SETVISIBLEREGION invalid context supplied %d!", pContext->enmType));
3287 Status = STATUS_INVALID_PARAMETER;
3288 break;
3289 }
3290#endif
3291 /* visible regions for seamless */
3292 LPRGNDATA lpRgnData = VBOXDISPIFESCAPE_DATA(pEscapeHdr, RGNDATA);
3293 uint32_t cbData = VBOXDISPIFESCAPE_DATA_SIZE(pEscape->PrivateDriverDataSize);
3294 uint32_t cbRects = cbData - RT_UOFFSETOF(RGNDATA, Buffer);
3295 /* the lpRgnData->Buffer comes to us as RECT
3296 * to avoid extra memcpy we cast it to PRTRECT assuming
3297 * they are identical
3298 * see AssertCompile's above */
3299
3300 RTRECT *pRect = (RTRECT *)&lpRgnData->Buffer;
3301
3302 uint32_t cRects = cbRects/sizeof(RTRECT);
3303 int rc;
3304
3305 LOG(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRects=%d", cRects));
3306 Assert(cbRects >= sizeof(RTRECT)
3307 && cbRects == cRects*sizeof(RTRECT)
3308 && cRects == lpRgnData->rdh.nCount);
3309 if ( cbRects >= sizeof(RTRECT)
3310 && cbRects == cRects*sizeof(RTRECT)
3311 && cRects == lpRgnData->rdh.nCount)
3312 {
3313 /*
3314 * Inform the host about the visible region
3315 */
3316 VMMDevVideoSetVisibleRegion *pReq = NULL;
3317
3318 rc = VbglR0GRAlloc ((VMMDevRequestHeader **)&pReq,
3319 sizeof (VMMDevVideoSetVisibleRegion) + (cRects-1)*sizeof(RTRECT),
3320 VMMDevReq_VideoSetVisibleRegion);
3321 AssertRC(rc);
3322 if (RT_SUCCESS(rc))
3323 {
3324 pReq->cRect = cRects;
3325 memcpy(&pReq->Rect, pRect, cRects*sizeof(RTRECT));
3326
3327 rc = VbglR0GRPerform (&pReq->header);
3328 AssertRC(rc);
3329 if (RT_SUCCESS(rc))
3330 Status = STATUS_SUCCESS;
3331 else
3332 {
3333 WARN(("VbglR0GRPerform failed rc (%d)", rc));
3334 Status = STATUS_UNSUCCESSFUL;
3335 }
3336 VbglR0GRFree(&pReq->header);
3337 }
3338 else
3339 {
3340 WARN(("VbglR0GRAlloc failed rc (%d)", rc));
3341 Status = STATUS_UNSUCCESSFUL;
3342 }
3343 }
3344 else
3345 {
3346 WARN(("VBOXESC_SETVISIBLEREGION: incorrect buffer size (%d), reported count (%d)", cbRects, lpRgnData->rdh.nCount));
3347 Status = STATUS_INVALID_PARAMETER;
3348 }
3349 break;
3350 }
3351 case VBOXESC_ISVRDPACTIVE:
3352 /** @todo implement */
3353 Status = STATUS_SUCCESS;
3354 break;
3355 case VBOXESC_CONFIGURETARGETS:
3356 {
3357 LOG(("=> VBOXESC_CONFIGURETARGETS"));
3358
3359 if (!pEscape->Flags.HardwareAccess)
3360 {
3361 WARN(("VBOXESC_CONFIGURETARGETS called without HardwareAccess flag set, failing"));
3362 Status = STATUS_INVALID_PARAMETER;
3363 break;
3364 }
3365
3366#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3367 /* win8.1 does not allow context-based escapes for display-only mode */
3368 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3369 if (!pContext)
3370 {
3371 WARN(("VBOXESC_CONFIGURETARGETS no context supplied!"));
3372 Status = STATUS_INVALID_PARAMETER;
3373 break;
3374 }
3375
3376 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE)
3377 {
3378 WARN(("VBOXESC_CONFIGURETARGETS invalid context supplied %d!", pContext->enmType));
3379 Status = STATUS_INVALID_PARAMETER;
3380 break;
3381 }
3382#endif
3383
3384 if (pEscape->PrivateDriverDataSize != sizeof (*pEscapeHdr))
3385 {
3386 WARN(("VBOXESC_CONFIGURETARGETS invalid private driver size %d", pEscape->PrivateDriverDataSize));
3387 Status = STATUS_INVALID_PARAMETER;
3388 break;
3389 }
3390
3391 if (pEscapeHdr->u32CmdSpecific)
3392 {
3393 WARN(("VBOXESC_CONFIGURETARGETS invalid command %d", pEscapeHdr->u32CmdSpecific));
3394 Status = STATUS_INVALID_PARAMETER;
3395 break;
3396 }
3397
3398 HANDLE hKey = NULL;
3399 uint32_t cAdjusted = 0;
3400
3401 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3402 {
3403 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
3404 if (pTarget->fConfigured)
3405 continue;
3406
3407 pTarget->fConfigured = true;
3408
3409 if (!pTarget->fConnected)
3410 {
3411 Status = VBoxWddmChildStatusConnect(pDevExt, (uint32_t)i, TRUE);
3412 if (NT_SUCCESS(Status))
3413 ++cAdjusted;
3414 else
3415 WARN(("VBOXESC_CONFIGURETARGETS vboxWddmChildStatusConnectSecondaries failed Status 0x%x\n", Status));
3416 }
3417
3418 if (!hKey)
3419 {
3420 Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE, &hKey);
3421 if (!NT_SUCCESS(Status))
3422 {
3423 WARN(("VBOXESC_CONFIGURETARGETS IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
3424 hKey = NULL;
3425 continue;
3426 }
3427 }
3428
3429 Assert(hKey);
3430
3431 WCHAR wszNameBuf[sizeof(VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX) / sizeof(WCHAR) + 32];
3432 RTUtf16Printf(wszNameBuf, RT_ELEMENTS(wszNameBuf), "%ls%d", VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX, i);
3433 Status = vboxWddmRegSetValueDword(hKey, wszNameBuf, VBOXWDDM_CFG_DRVTARGET_CONNECTED);
3434 if (!NT_SUCCESS(Status))
3435 WARN(("VBOXESC_CONFIGURETARGETS vboxWddmRegSetValueDword (%ls) failed Status 0x%x\n", wszNameBuf, Status));
3436
3437 }
3438
3439 if (hKey)
3440 {
3441 NTSTATUS rcNt2 = ZwClose(hKey);
3442 Assert(rcNt2 == STATUS_SUCCESS); NOREF(rcNt2);
3443 }
3444
3445 pEscapeHdr->u32CmdSpecific = cAdjusted;
3446
3447 Status = STATUS_SUCCESS;
3448
3449 LOG(("<= VBOXESC_CONFIGURETARGETS"));
3450 break;
3451 }
3452 case VBOXESC_SETALLOCHOSTID:
3453 {
3454 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)pEscape->hDevice;
3455 if (!pDevice)
3456 {
3457 WARN(("VBOXESC_SETALLOCHOSTID called without no device specified, failing"));
3458 Status = STATUS_INVALID_PARAMETER;
3459 break;
3460 }
3461
3462 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_SETALLOCHOSTID))
3463 {
3464 WARN(("invalid buffer size for VBOXDISPIFESCAPE_SETALLOCHOSTID, was(%d), but expected (%d)",
3465 pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE_SETALLOCHOSTID)));
3466 Status = STATUS_INVALID_PARAMETER;
3467 break;
3468 }
3469
3470 if (!pEscape->Flags.HardwareAccess)
3471 {
3472 WARN(("VBOXESC_SETALLOCHOSTID not HardwareAccess"));
3473 Status = STATUS_INVALID_PARAMETER;
3474 break;
3475 }
3476
3477 PVBOXDISPIFESCAPE_SETALLOCHOSTID pSetHostID = (PVBOXDISPIFESCAPE_SETALLOCHOSTID)pEscapeHdr;
3478 PVBOXWDDM_ALLOCATION pAlloc = vboxWddmGetAllocationFromHandle(pDevExt, (D3DKMT_HANDLE)pSetHostID->hAlloc);
3479 if (!pAlloc)
3480 {
3481 WARN(("failed to get allocation from handle"));
3482 Status = STATUS_INVALID_PARAMETER;
3483 break;
3484 }
3485
3486 if (pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_D3D)
3487 {
3488 pSetHostID->EscapeHdr.u32CmdSpecific = pAlloc->dx.sid;
3489 pSetHostID->rc = VERR_NOT_EQUAL;
3490 Status = STATUS_SUCCESS;
3491 break;
3492 }
3493
3494 if (pAlloc->enmType != VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE)
3495 {
3496 WARN(("setHostID: invalid allocation type: %d", pAlloc->enmType));
3497 Status = STATUS_INVALID_PARAMETER;
3498 break;
3499 }
3500
3501 pSetHostID->rc = VBoxWddmOaSetHostID(pDevice, pAlloc, pSetHostID->hostID, &pSetHostID->EscapeHdr.u32CmdSpecific);
3502
3503 if (pAlloc->bAssigned)
3504 {
3505 PVBOXMP_DEVEXT pDevExt2 = pDevice->pAdapter;
3506 Assert(pAlloc->AllocData.SurfDesc.VidPnSourceId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt2)->cDisplays);
3507 PVBOXWDDM_SOURCE pSource = &pDevExt2->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
3508 if (pSource->AllocData.hostID != pAlloc->AllocData.hostID)
3509 {
3510 pSource->AllocData.hostID = pAlloc->AllocData.hostID;
3511 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
3512
3513 vboxWddmGhDisplayCheckSetInfo(pDevExt2);
3514 }
3515 }
3516
3517 Status = STATUS_SUCCESS;
3518 break;
3519 }
3520 case VBOXESC_ISANYX:
3521 {
3522 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_ISANYX))
3523 {
3524 WARN(("invalid private driver size %d", pEscape->PrivateDriverDataSize));
3525 Status = STATUS_INVALID_PARAMETER;
3526 break;
3527 }
3528
3529 PVBOXDISPIFESCAPE_ISANYX pIsAnyX = (PVBOXDISPIFESCAPE_ISANYX)pEscapeHdr;
3530 pIsAnyX->u32IsAnyX = VBoxCommonFromDeviceExt(pDevExt)->fAnyX;
3531 Status = STATUS_SUCCESS;
3532 break;
3533 }
3534 case VBOXESC_UPDATEMODES:
3535 {
3536 LOG(("=> VBOXESC_UPDATEMODES"));
3537
3538 if (!pEscape->Flags.HardwareAccess)
3539 {
3540 WARN(("VBOXESC_UPDATEMODES called without HardwareAccess flag set, failing"));
3541 Status = STATUS_INVALID_PARAMETER;
3542 break;
3543 }
3544
3545#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3546 /* win8.1 does not allow context-based escapes for display-only mode */
3547 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3548 if (!pContext)
3549 {
3550 WARN(("VBOXESC_UPDATEMODES no context supplied!"));
3551 Status = STATUS_INVALID_PARAMETER;
3552 break;
3553 }
3554
3555 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE)
3556 {
3557 WARN(("VBOXESC_UPDATEMODES invalid context supplied %d!", pContext->enmType));
3558 Status = STATUS_INVALID_PARAMETER;
3559 break;
3560 }
3561#endif
3562
3563 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_UPDATEMODES))
3564 {
3565 WARN(("VBOXESC_UPDATEMODES invalid private driver size %d", pEscape->PrivateDriverDataSize));
3566 Status = STATUS_INVALID_PARAMETER;
3567 break;
3568 }
3569
3570 VBOXDISPIFESCAPE_UPDATEMODES *pData = (VBOXDISPIFESCAPE_UPDATEMODES*)pEscapeHdr;
3571 Status = VBoxVidPnUpdateModes(pDevExt, pData->u32TargetId, &pData->Size);
3572 if (!NT_SUCCESS(Status))
3573 {
3574 WARN(("VBoxVidPnUpdateModes failed Status(%#x)\n", Status));
3575 return Status;
3576 }
3577
3578 Status = STATUS_SUCCESS;
3579 break;
3580 }
3581 case VBOXESC_TARGET_CONNECTIVITY:
3582 {
3583 if (!pEscape->Flags.HardwareAccess)
3584 {
3585 WARN(("VBOXESC_TARGET_CONNECTIVITY called without HardwareAccess flag set, failing"));
3586 Status = STATUS_INVALID_PARAMETER;
3587 break;
3588 }
3589
3590 if (pEscape->PrivateDriverDataSize != sizeof(VBOXDISPIFESCAPE_TARGETCONNECTIVITY))
3591 {
3592 WARN(("VBOXESC_TARGET_CONNECTIVITY invalid private driver size %d", pEscape->PrivateDriverDataSize));
3593 Status = STATUS_INVALID_PARAMETER;
3594 break;
3595 }
3596
3597 VBOXDISPIFESCAPE_TARGETCONNECTIVITY *pData = (VBOXDISPIFESCAPE_TARGETCONNECTIVITY *)pEscapeHdr;
3598 LOG(("=> VBOXESC_TARGET_CONNECTIVITY[%d] 0x%08X", pData->u32TargetId, pData->fu32Connect));
3599
3600 if (pData->u32TargetId >= (uint32_t)VBoxCommonFromDeviceExt(pDevExt)->cDisplays)
3601 {
3602 WARN(("VBOXESC_TARGET_CONNECTIVITY invalid screen index 0x%x", pData->u32TargetId));
3603 Status = STATUS_INVALID_PARAMETER;
3604 break;
3605 }
3606
3607 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[pData->u32TargetId];
3608 pTarget->fDisabled = !RT_BOOL(pData->fu32Connect & 1);
3609 pTarget->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_TOPOLOGY;
3610
3611 Status = STATUS_SUCCESS;
3612 break;
3613 }
3614 case VBOXESC_DBGPRINT:
3615 {
3616 /* use RT_OFFSETOF instead of sizeof since sizeof will give an aligned size that might
3617 * be bigger than the VBOXDISPIFESCAPE_DBGPRINT with a data containing just a few chars */
3618 Assert(pEscape->PrivateDriverDataSize >= RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]));
3619 /* only do DbgPrint when pEscape->PrivateDriverDataSize > RT_OFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1])
3620 * since == RT_OFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]) means the buffer contains just \0,
3621 * i.e. no need to print it */
3622 if (pEscape->PrivateDriverDataSize > RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]))
3623 {
3624 PVBOXDISPIFESCAPE_DBGPRINT pDbgPrint = (PVBOXDISPIFESCAPE_DBGPRINT)pEscapeHdr;
3625 /* ensure the last char is \0*/
3626 if (*((uint8_t*)pDbgPrint + pEscape->PrivateDriverDataSize - 1) == '\0')
3627 {
3628 if (g_VBoxLogUm & VBOXWDDM_CFG_LOG_UM_DBGPRINT)
3629 DbgPrint("%s\n", pDbgPrint->aStringBuf);
3630 if (g_VBoxLogUm & VBOXWDDM_CFG_LOG_UM_BACKDOOR)
3631 LOGREL_EXACT(("%s\n", pDbgPrint->aStringBuf));
3632 }
3633 }
3634 Status = STATUS_SUCCESS;
3635 break;
3636 }
3637 case VBOXESC_DBGDUMPBUF:
3638 {
3639 Status = vboxUmdDumpBuf((PVBOXDISPIFESCAPE_DBGDUMPBUF)pEscapeHdr, pEscape->PrivateDriverDataSize);
3640 break;
3641 }
3642 case VBOXESC_GUEST_DISPLAYCHANGED:
3643 {
3644 LOG(("=> VBOXESC_GUEST_DISPLAYCHANGED"));
3645
3646 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3647 {
3648#ifdef VBOX_WITH_VMSVGA
3649 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3650 {
3651 GaVidPnSourceCheckPos(pDevExt, i);
3652 continue;
3653 }
3654#endif
3655
3656 vboxWddmDisplaySettingsCheckPos(pDevExt, i);
3657 }
3658 Status = STATUS_SUCCESS;
3659 break;
3660 }
3661 default:
3662#ifdef VBOX_WITH_VMSVGA
3663 Status = GaDxgkDdiEscape(hAdapter, pEscape);
3664 if (NT_SUCCESS(Status) || Status != STATUS_NOT_SUPPORTED)
3665 break;
3666#endif
3667 WARN(("unsupported escape code (0x%x)", pEscapeHdr->escapeCode));
3668 break;
3669 }
3670 }
3671 else
3672 {
3673 WARN(("pEscape->PrivateDriverDataSize(%d) < (%d)", pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE)));
3674 Status = STATUS_BUFFER_TOO_SMALL;
3675 }
3676
3677// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3678
3679 return Status;
3680}
3681
3682NTSTATUS
3683APIENTRY
3684DxgkDdiCollectDbgInfo(
3685 CONST HANDLE hAdapter,
3686 CONST DXGKARG_COLLECTDBGINFO* pCollectDbgInfo
3687 )
3688{
3689 RT_NOREF(hAdapter, pCollectDbgInfo);
3690 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3691
3692 AssertBreakpoint();
3693
3694 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3695
3696 return STATUS_SUCCESS;
3697}
3698
3699NTSTATUS
3700APIENTRY
3701DxgkDdiIsSupportedVidPn(
3702 CONST HANDLE hAdapter,
3703 OUT DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPnArg
3704 )
3705{
3706 /* The DxgkDdiIsSupportedVidPn should be made pageable. */
3707 PAGED_CODE();
3708
3709 LOGF(("ENTER, context(0x%x)", hAdapter));
3710
3711 vboxVDbgBreakFv();
3712
3713 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3714 NTSTATUS Status = VBoxVidPnIsSupported(pDevExt, pIsSupportedVidPnArg->hDesiredVidPn, &pIsSupportedVidPnArg->IsVidPnSupported);
3715 if (!NT_SUCCESS(Status))
3716 {
3717 WARN(("VBoxVidPnIsSupported failed Status(%#x)\n", Status));
3718 return Status;
3719 }
3720
3721 LOGF(("LEAVE, isSupported(%d), context(0x%x)", pIsSupportedVidPnArg->IsVidPnSupported, hAdapter));
3722
3723 return STATUS_SUCCESS;
3724}
3725
3726NTSTATUS
3727APIENTRY
3728DxgkDdiRecommendFunctionalVidPn(
3729 CONST HANDLE hAdapter,
3730 CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPnArg
3731 )
3732{
3733 /* The DxgkDdiRecommendFunctionalVidPn should be made pageable. */
3734 PAGED_CODE();
3735
3736 LOGF(("ENTER, context(0x%x)", hAdapter));
3737
3738 vboxVDbgBreakFv();
3739
3740 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3741
3742 if (pRecommendFunctionalVidPnArg->PrivateDriverDataSize != sizeof (VBOXWDDM_RECOMMENDVIDPN))
3743 {
3744 WARN(("invalid size"));
3745 return STATUS_INVALID_PARAMETER;
3746 }
3747
3748 VBOXWDDM_RECOMMENDVIDPN *pData = (VBOXWDDM_RECOMMENDVIDPN*)pRecommendFunctionalVidPnArg->pPrivateDriverData;
3749 Assert(pData);
3750
3751 NTSTATUS Status = VBoxVidPnRecommendFunctional(pDevExt, pRecommendFunctionalVidPnArg->hRecommendedFunctionalVidPn, pData);
3752 if (!NT_SUCCESS(Status))
3753 {
3754 WARN(("VBoxVidPnRecommendFunctional failed %#x", Status));
3755 return Status;
3756 }
3757
3758 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3759
3760 return STATUS_SUCCESS;
3761}
3762
3763NTSTATUS
3764APIENTRY
3765DxgkDdiEnumVidPnCofuncModality(
3766 CONST HANDLE hAdapter,
3767 CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModalityArg
3768 )
3769{
3770 /* The DxgkDdiEnumVidPnCofuncModality function should be made pageable. */
3771 PAGED_CODE();
3772
3773 LOGF(("ENTER, context(0x%x)", hAdapter));
3774
3775 vboxVDbgBreakFv();
3776
3777 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3778
3779 NTSTATUS Status = VBoxVidPnCofuncModality(pDevExt, pEnumCofuncModalityArg->hConstrainingVidPn, pEnumCofuncModalityArg->EnumPivotType, &pEnumCofuncModalityArg->EnumPivot);
3780 if (!NT_SUCCESS(Status))
3781 {
3782 WARN(("VBoxVidPnCofuncModality failed Status(%#x)\n", Status));
3783 return Status;
3784 }
3785
3786 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3787
3788 return STATUS_SUCCESS;
3789}
3790
3791NTSTATUS
3792APIENTRY
3793DxgkDdiSetVidPnSourceAddress(
3794 CONST HANDLE hAdapter,
3795 CONST DXGKARG_SETVIDPNSOURCEADDRESS* pSetVidPnSourceAddress
3796 )
3797{
3798 /* The DxgkDdiSetVidPnSourceAddress function should be made pageable. */
3799 PAGED_CODE();
3800
3801 vboxVDbgBreakFv();
3802
3803 LOGF(("ENTER, context(0x%x)", hAdapter));
3804 LOG(("id %d, seg %d, addr 0x%RX64, hAllocation %p, ctx cnt %d, f 0x%x",
3805 pSetVidPnSourceAddress->VidPnSourceId,
3806 pSetVidPnSourceAddress->PrimarySegment,
3807 pSetVidPnSourceAddress->PrimaryAddress.QuadPart,
3808 pSetVidPnSourceAddress->hAllocation,
3809 pSetVidPnSourceAddress->ContextCount,
3810 pSetVidPnSourceAddress->Flags.Value));
3811
3812 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3813 if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceAddress->VidPnSourceId)
3814 {
3815 WARN(("invalid VidPnSourceId (%d), for displays(%d)", pSetVidPnSourceAddress->VidPnSourceId, VBoxCommonFromDeviceExt(pDevExt)->cDisplays));
3816 return STATUS_INVALID_PARAMETER;
3817 }
3818
3819#ifdef VBOX_WITH_VMSVGA
3820 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VMSVGA)
3821#endif
3822 vboxWddmDisplaySettingsCheckPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId);
3823
3824 NTSTATUS Status = STATUS_SUCCESS;
3825 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceAddress->VidPnSourceId];
3826
3827 /*
3828 * Update the source VRAM address.
3829 */
3830 PVBOXWDDM_ALLOCATION pAllocation;
3831 Assert(pSetVidPnSourceAddress->hAllocation);
3832 Assert(pSetVidPnSourceAddress->hAllocation || pSource->pPrimaryAllocation);
3833 Assert (pSetVidPnSourceAddress->Flags.Value < 2); /* i.e. 0 or 1 (ModeChange) */
3834
3835 if (pSetVidPnSourceAddress->hAllocation)
3836 {
3837 pAllocation = (PVBOXWDDM_ALLOCATION)pSetVidPnSourceAddress->hAllocation;
3838 vboxWddmAssignPrimary(pSource, pAllocation, pSetVidPnSourceAddress->VidPnSourceId);
3839 }
3840 else
3841 pAllocation = pSource->pPrimaryAllocation;
3842
3843 if (pAllocation)
3844 {
3845 vboxWddmAddrSetVram(&pAllocation->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment, (VBOXVIDEOOFFSET)pSetVidPnSourceAddress->PrimaryAddress.QuadPart);
3846 }
3847
3848 if (g_VBoxDisplayOnly && !pAllocation)
3849 {
3850 /* the VRAM here is an absolute address, nto an offset!
3851 * convert to offset since all internal VBox functionality is offset-based */
3852 vboxWddmAddrSetVram(&pSource->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment,
3853 vboxWddmVramAddrToOffset(pDevExt, pSetVidPnSourceAddress->PrimaryAddress));
3854 }
3855 else
3856 {
3857 Assert(!g_VBoxDisplayOnly);
3858 vboxWddmAddrSetVram(&pSource->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment,
3859 pSetVidPnSourceAddress->PrimaryAddress.QuadPart);
3860 }
3861
3862 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
3863
3864 /*
3865 * Report the source.
3866 */
3867#ifdef VBOX_WITH_VMSVGA
3868 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3869 {
3870 /* Query the position of the screen to make sure it is up to date. */
3871 vboxWddmDisplaySettingsQueryPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId, &pSource->VScreenPos);
3872
3873 GaVidPnSourceReport(pDevExt, pSource);
3874 return STATUS_SUCCESS;
3875 }
3876#endif
3877
3878 vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
3879
3880 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3881
3882 return Status;
3883}
3884
3885NTSTATUS
3886APIENTRY
3887DxgkDdiSetVidPnSourceVisibility(
3888 CONST HANDLE hAdapter,
3889 CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility
3890 )
3891{
3892 /* DxgkDdiSetVidPnSourceVisibility should be made pageable. */
3893 PAGED_CODE();
3894
3895 vboxVDbgBreakFv();
3896
3897 LOGF(("ENTER, context(0x%x)", hAdapter));
3898
3899 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3900
3901 if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceVisibility->VidPnSourceId)
3902 {
3903 WARN(("invalid VidPnSourceId (%d), for displays(%d)", pSetVidPnSourceVisibility->VidPnSourceId, VBoxCommonFromDeviceExt(pDevExt)->cDisplays));
3904 return STATUS_INVALID_PARAMETER;
3905 }
3906
3907#ifdef VBOX_WITH_VMSVGA
3908 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VMSVGA)
3909#endif
3910 vboxWddmDisplaySettingsCheckPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId);
3911
3912 NTSTATUS Status = STATUS_SUCCESS;
3913 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceVisibility->VidPnSourceId];
3914 PVBOXWDDM_ALLOCATION pAllocation = pSource->pPrimaryAllocation;
3915 if (pAllocation)
3916 {
3917 Assert(pAllocation->bVisible == pSource->bVisible);
3918 pAllocation->bVisible = pSetVidPnSourceVisibility->Visible;
3919 }
3920
3921 if (pSource->bVisible != pSetVidPnSourceVisibility->Visible)
3922 {
3923 pSource->bVisible = pSetVidPnSourceVisibility->Visible;
3924// pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_VISIBILITY;
3925// if (pDevExt->fCmdVbvaEnabled || pSource->bVisible)
3926// {
3927// vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
3928// }
3929 }
3930
3931#ifdef VBOX_WITH_VMSVGA
3932 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3933 {
3934 GaVidPnSourceCheckPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId);
3935 }
3936#endif
3937
3938 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3939
3940 return Status;
3941}
3942
3943NTSTATUS
3944APIENTRY
3945DxgkDdiCommitVidPn(
3946 CONST HANDLE hAdapter,
3947 CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPnArg
3948 )
3949{
3950 LOG(("ENTER AffectedVidPnSourceId(%d) hAdapter(0x%x)", pCommitVidPnArg->AffectedVidPnSourceId, hAdapter));
3951
3952 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3953 NTSTATUS Status;
3954
3955 vboxVDbgBreakFv();
3956
3957 VBOXWDDM_SOURCE *paSources = (VBOXWDDM_SOURCE*)RTMemAlloc(sizeof (VBOXWDDM_SOURCE) * VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3958 if (!paSources)
3959 {
3960 WARN(("RTMemAlloc failed"));
3961 return STATUS_NO_MEMORY;
3962 }
3963
3964 VBOXWDDM_TARGET *paTargets = (VBOXWDDM_TARGET*)RTMemAlloc(sizeof (VBOXWDDM_TARGET) * VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3965 if (!paTargets)
3966 {
3967 WARN(("RTMemAlloc failed"));
3968 RTMemFree(paSources);
3969 return STATUS_NO_MEMORY;
3970 }
3971
3972 VBoxVidPnSourcesInit(paSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, VBOXWDDM_HGSYNC_F_SYNCED_ALL);
3973
3974 VBoxVidPnTargetsInit(paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, VBOXWDDM_HGSYNC_F_SYNCED_ALL);
3975
3976 VBoxVidPnSourcesCopy(paSources, pDevExt->aSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3977 VBoxVidPnTargetsCopy(paTargets, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3978
3979 do {
3980 const DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
3981 Status = pDevExt->u.primary.DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPnArg->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
3982 if (!NT_SUCCESS(Status))
3983 {
3984 WARN(("DxgkCbQueryVidPnInterface failed Status 0x%x", Status));
3985 break;
3986 }
3987
3988#ifdef VBOXWDDM_DEBUG_VIDPN
3989 vboxVidPnDumpVidPn("\n>>>>COMMIT VidPN: >>>>", pDevExt, pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface, "<<<<<<<<<<<<<<<<<<<<\n");
3990#endif
3991
3992 if (pCommitVidPnArg->AffectedVidPnSourceId != D3DDDI_ID_ALL)
3993 {
3994 Status = VBoxVidPnCommitSourceModeForSrcId(
3995 pDevExt,
3996 pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface,
3997 (PVBOXWDDM_ALLOCATION)pCommitVidPnArg->hPrimaryAllocation,
3998 pCommitVidPnArg->AffectedVidPnSourceId, paSources, paTargets, pCommitVidPnArg->Flags.PathPowerTransition);
3999 if (!NT_SUCCESS(Status))
4000 {
4001 WARN(("VBoxVidPnCommitSourceModeForSrcId for current VidPn failed Status 0x%x", Status));
4002 break;
4003 }
4004 }
4005 else
4006 {
4007 Status = VBoxVidPnCommitAll(pDevExt, pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface,
4008 (PVBOXWDDM_ALLOCATION)pCommitVidPnArg->hPrimaryAllocation,
4009 paSources, paTargets);
4010 if (!NT_SUCCESS(Status))
4011 {
4012 WARN(("VBoxVidPnCommitAll for current VidPn failed Status 0x%x", Status));
4013 break;
4014 }
4015 }
4016
4017 Assert(NT_SUCCESS(Status));
4018 pDevExt->u.primary.hCommittedVidPn = pCommitVidPnArg->hFunctionalVidPn;
4019 VBoxVidPnSourcesCopy(pDevExt->aSources, paSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
4020 VBoxVidPnTargetsCopy(pDevExt->aTargets, paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
4021
4022 VBoxDumpSourceTargetArrays(paSources, paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
4023
4024#ifdef VBOX_WITH_VMSVGA
4025 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4026 {
4027 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
4028 {
4029 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[i];
4030
4031 LOG(("Source [%d]: visible %d, blanked %d", i, pSource->bVisible, pSource->bBlankedByPowerOff));
4032
4033 /* Update positions of all screens. */
4034 vboxWddmDisplaySettingsQueryPos(pDevExt, i, &pSource->VScreenPos);
4035
4036 GaVidPnSourceReport(pDevExt, pSource);
4037 }
4038
4039 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
4040 {
4041 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
4042 Assert(pTarget->u32Id == (unsigned)i);
4043 if (pTarget->VidPnSourceId != D3DDDI_ID_UNINITIALIZED)
4044 {
4045 continue;
4046 }
4047
4048 LOG(("Target [%d]: blanked %d", i, pTarget->fBlankedByPowerOff));
4049
4050 if (pTarget->fBlankedByPowerOff)
4051 {
4052 GaScreenDefine(pDevExt->pGa, 0, pTarget->u32Id, 0, 0, 0, 0, true);
4053 }
4054 else
4055 {
4056 GaScreenDestroy(pDevExt->pGa, pTarget->u32Id);
4057 }
4058 }
4059
4060 break;
4061 }
4062#endif
4063 vboxWddmGhDisplayCheckSetInfo(pDevExt);
4064 } while (0);
4065
4066 RTMemFree(paSources);
4067 RTMemFree(paTargets);
4068
4069 LOG(("LEAVE, status(0x%x), hAdapter(0x%x)", Status, hAdapter));
4070
4071 return Status;
4072}
4073
4074NTSTATUS
4075APIENTRY
4076DxgkDdiUpdateActiveVidPnPresentPath(
4077 CONST HANDLE hAdapter,
4078 CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPathArg
4079 )
4080{
4081 RT_NOREF(hAdapter, pUpdateActiveVidPnPresentPathArg);
4082 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4083
4084 AssertBreakpoint();
4085
4086 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4087
4088 return STATUS_SUCCESS;
4089}
4090
4091NTSTATUS
4092APIENTRY
4093DxgkDdiRecommendMonitorModes(
4094 CONST HANDLE hAdapter,
4095 CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModesArg
4096 )
4097{
4098 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4099
4100 vboxVDbgBreakFv();
4101
4102 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4103
4104 NTSTATUS Status = VBoxVidPnRecommendMonitorModes(pDevExt, pRecommendMonitorModesArg->VideoPresentTargetId,
4105 pRecommendMonitorModesArg->hMonitorSourceModeSet, pRecommendMonitorModesArg->pMonitorSourceModeSetInterface);
4106 if (!NT_SUCCESS(Status))
4107 {
4108 WARN(("VBoxVidPnRecommendMonitorModes failed %#x", Status));
4109 return Status;
4110 }
4111
4112 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4113
4114 return STATUS_SUCCESS;
4115}
4116
4117NTSTATUS
4118APIENTRY
4119DxgkDdiRecommendVidPnTopology(
4120 CONST HANDLE hAdapter,
4121 CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopologyArg
4122 )
4123{
4124 RT_NOREF(hAdapter, pRecommendVidPnTopologyArg);
4125 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4126
4127 vboxVDbgBreakFv();
4128
4129 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4130
4131 return STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY;
4132}
4133
4134NTSTATUS
4135APIENTRY
4136DxgkDdiGetScanLine(
4137 CONST HANDLE hAdapter,
4138 DXGKARG_GETSCANLINE* pGetScanLine)
4139{
4140 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4141
4142 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4143
4144#ifdef DEBUG_misha
4145// RT_BREAKPOINT();
4146#endif
4147
4148 NTSTATUS Status = VBoxWddmSlGetScanLine(pDevExt, pGetScanLine);
4149
4150 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4151
4152 return Status;
4153}
4154
4155NTSTATUS
4156APIENTRY
4157DxgkDdiStopCapture(
4158 CONST HANDLE hAdapter,
4159 CONST DXGKARG_STOPCAPTURE* pStopCapture)
4160{
4161 RT_NOREF(hAdapter, pStopCapture);
4162 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4163
4164 AssertBreakpoint();
4165
4166 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4167
4168 return STATUS_SUCCESS;
4169}
4170
4171NTSTATUS
4172APIENTRY
4173DxgkDdiControlInterrupt(
4174 CONST HANDLE hAdapter,
4175 CONST DXGK_INTERRUPT_TYPE InterruptType,
4176 BOOLEAN Enable
4177 )
4178{
4179 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4180
4181 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
4182 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4183
4184 switch (InterruptType)
4185 {
4186 case DXGK_INTERRUPT_DISPLAYONLY_VSYNC:
4187 case DXGK_INTERRUPT_CRTC_VSYNC:
4188 {
4189 Status = VBoxWddmSlEnableVSyncNotification(pDevExt, Enable);
4190 if (NT_SUCCESS(Status))
4191 Status = STATUS_SUCCESS; /* <- sanity */
4192 else
4193 WARN(("VSYNC Interrupt control failed Enable(%d), Status(0x%x)", Enable, Status));
4194 break;
4195 }
4196 case DXGK_INTERRUPT_DMA_COMPLETED:
4197 case DXGK_INTERRUPT_DMA_PREEMPTED:
4198 case DXGK_INTERRUPT_DMA_FAULTED:
4199 WARN(("Unexpected interrupt type! %d", InterruptType));
4200 break;
4201 default:
4202 WARN(("UNSUPPORTED interrupt type! %d", InterruptType));
4203 break;
4204 }
4205
4206 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4207
4208 return Status;
4209}
4210
4211NTSTATUS
4212APIENTRY
4213DxgkDdiCreateOverlay(
4214 CONST HANDLE hAdapter,
4215 DXGKARG_CREATEOVERLAY *pCreateOverlay)
4216{
4217 LOGF(("ENTER, hAdapter(0x%p)", hAdapter));
4218
4219 NTSTATUS Status = STATUS_SUCCESS;
4220
4221#ifdef VBOX_WITH_VIDEOHWACCEL
4222 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4223 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)vboxWddmMemAllocZero(sizeof (VBOXWDDM_OVERLAY));
4224 Assert(pOverlay);
4225 if (pOverlay)
4226 {
4227 int rc = vboxVhwaHlpOverlayCreate(pDevExt, pCreateOverlay->VidPnSourceId, &pCreateOverlay->OverlayInfo, pOverlay);
4228 AssertRC(rc);
4229 if (RT_SUCCESS(rc))
4230 {
4231 pCreateOverlay->hOverlay = pOverlay;
4232 }
4233 else
4234 {
4235 vboxWddmMemFree(pOverlay);
4236 Status = STATUS_UNSUCCESSFUL;
4237 }
4238 }
4239 else
4240 Status = STATUS_NO_MEMORY;
4241#else
4242 RT_NOREF(hAdapter, pCreateOverlay);
4243#endif
4244
4245 LOGF(("LEAVE, hAdapter(0x%p)", hAdapter));
4246
4247 return Status;
4248}
4249
4250NTSTATUS
4251APIENTRY
4252DxgkDdiDestroyDevice(
4253 CONST HANDLE hDevice)
4254{
4255 /* DxgkDdiDestroyDevice should be made pageable. */
4256 PAGED_CODE();
4257
4258 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4259
4260 vboxVDbgBreakFv();
4261
4262#ifdef VBOX_WITH_VMSVGA
4263 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4264 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4265 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4266 {
4267 GaDeviceDestroy(pDevExt->pGa, pDevice);
4268 }
4269#endif
4270
4271 vboxWddmMemFree(hDevice);
4272
4273 LOGF(("LEAVE, "));
4274
4275 return STATUS_SUCCESS;
4276}
4277
4278
4279
4280/*
4281 * DxgkDdiOpenAllocation
4282 */
4283NTSTATUS
4284APIENTRY
4285DxgkDdiOpenAllocation(
4286 CONST HANDLE hDevice,
4287 CONST DXGKARG_OPENALLOCATION *pOpenAllocation)
4288{
4289 /* DxgkDdiOpenAllocation should be made pageable. */
4290 PAGED_CODE();
4291
4292 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4293
4294 vboxVDbgBreakFv();
4295
4296 NTSTATUS Status = STATUS_SUCCESS;
4297 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4298 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4299 PVBOXWDDM_RCINFO pRcInfo = NULL;
4300 if (pOpenAllocation->PrivateDriverSize)
4301 {
4302 Assert(pOpenAllocation->pPrivateDriverData);
4303 if (pOpenAllocation->PrivateDriverSize == sizeof (VBOXWDDM_RCINFO))
4304 {
4305 pRcInfo = (PVBOXWDDM_RCINFO)pOpenAllocation->pPrivateDriverData;
4306 Assert(pRcInfo->cAllocInfos == pOpenAllocation->NumAllocations);
4307 }
4308 else
4309 {
4310 WARN(("Invalid PrivateDriverSize %d", pOpenAllocation->PrivateDriverSize));
4311 Status = STATUS_INVALID_PARAMETER;
4312 }
4313 }
4314
4315 if (Status == STATUS_SUCCESS)
4316 {
4317 UINT i = 0;
4318 for (; i < pOpenAllocation->NumAllocations; ++i)
4319 {
4320 DXGK_OPENALLOCATIONINFO* pInfo = &pOpenAllocation->pOpenAllocation[i];
4321#ifdef VBOX_WITH_VMSVGA3D_DX
4322 Assert( pInfo->PrivateDriverDataSize == sizeof(VBOXDXALLOCATIONDESC)
4323 || pInfo->PrivateDriverDataSize == sizeof(VBOXWDDM_ALLOCINFO));
4324#else
4325 Assert(pInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_ALLOCINFO));
4326#endif
4327 Assert(pInfo->pPrivateDriverData);
4328 PVBOXWDDM_ALLOCATION pAllocation = vboxWddmGetAllocationFromHandle(pDevExt, pInfo->hAllocation);
4329 if (!pAllocation)
4330 {
4331 WARN(("invalid handle"));
4332 Status = STATUS_INVALID_PARAMETER;
4333 break;
4334 }
4335
4336#ifdef DEBUG
4337 Assert(!pAllocation->fAssumedDeletion);
4338#endif
4339 if (pRcInfo)
4340 {
4341 Assert(pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC);
4342
4343 if (pInfo->PrivateDriverDataSize != sizeof (VBOXWDDM_ALLOCINFO)
4344 || !pInfo->pPrivateDriverData)
4345 {
4346 WARN(("invalid data size"));
4347 Status = STATUS_INVALID_PARAMETER;
4348 break;
4349 }
4350
4351#ifdef VBOX_WITH_VIDEOHWACCEL
4352 PVBOXWDDM_ALLOCINFO pAllocInfo = (PVBOXWDDM_ALLOCINFO)pInfo->pPrivateDriverData;
4353
4354 if (pRcInfo->RcDesc.fFlags.Overlay)
4355 {
4356 /* we have queried host for some surface info, like pitch & size,
4357 * need to return it back to the UMD (User Mode Drive) */
4358 pAllocInfo->SurfDesc = pAllocation->AllocData.SurfDesc;
4359 /* success, just continue */
4360 }
4361#endif
4362 }
4363
4364 KIRQL OldIrql;
4365 PVBOXWDDM_OPENALLOCATION pOa;
4366 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
4367 pOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
4368 if (pOa)
4369 {
4370 ++pOa->cOpens;
4371 ++pAllocation->cOpens;
4372 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4373 }
4374 else
4375 {
4376 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4377 pOa = (PVBOXWDDM_OPENALLOCATION)vboxWddmMemAllocZero(sizeof (VBOXWDDM_OPENALLOCATION));
4378 if (!pOa)
4379 {
4380 WARN(("failed to allocation alloc info"));
4381 Status = STATUS_INSUFFICIENT_RESOURCES;
4382 break;
4383 }
4384
4385 pOa->hAllocation = pInfo->hAllocation;
4386 pOa->pAllocation = pAllocation;
4387 pOa->pDevice = pDevice;
4388 pOa->cOpens = 1;
4389
4390 PVBOXWDDM_OPENALLOCATION pConcurrentOa;
4391 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
4392 pConcurrentOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
4393 if (!pConcurrentOa)
4394 InsertHeadList(&pAllocation->OpenList, &pOa->ListEntry);
4395 else
4396 ++pConcurrentOa->cOpens;
4397 ++pAllocation->cOpens;
4398 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4399 if (pConcurrentOa)
4400 {
4401 vboxWddmMemFree(pOa);
4402 pOa = pConcurrentOa;
4403 }
4404 }
4405
4406 pInfo->hDeviceSpecificAllocation = pOa;
4407 }
4408
4409 if (Status != STATUS_SUCCESS)
4410 {
4411 for (UINT j = 0; j < i; ++j)
4412 {
4413 DXGK_OPENALLOCATIONINFO* pInfo2Free = &pOpenAllocation->pOpenAllocation[j];
4414 PVBOXWDDM_OPENALLOCATION pOa2Free = (PVBOXWDDM_OPENALLOCATION)pInfo2Free->hDeviceSpecificAllocation;
4415 VBoxWddmOaRelease(pOa2Free);
4416 }
4417 }
4418 }
4419 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4420
4421 return Status;
4422}
4423
4424NTSTATUS
4425APIENTRY
4426DxgkDdiCloseAllocation(
4427 CONST HANDLE hDevice,
4428 CONST DXGKARG_CLOSEALLOCATION* pCloseAllocation)
4429{
4430 RT_NOREF(hDevice);
4431 /* DxgkDdiCloseAllocation should be made pageable. */
4432 PAGED_CODE();
4433
4434 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4435
4436 vboxVDbgBreakFv();
4437
4438 for (UINT i = 0; i < pCloseAllocation->NumAllocations; ++i)
4439 {
4440 PVBOXWDDM_OPENALLOCATION pOa2Free = (PVBOXWDDM_OPENALLOCATION)pCloseAllocation->pOpenHandleList[i];
4441 PVBOXWDDM_ALLOCATION pAllocation = pOa2Free->pAllocation;
4442 Assert(pAllocation->cShRcRefs >= pOa2Free->cShRcRefs);
4443 pAllocation->cShRcRefs -= pOa2Free->cShRcRefs;
4444 VBoxWddmOaRelease(pOa2Free);
4445 }
4446
4447 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4448
4449 return STATUS_SUCCESS;
4450}
4451
4452#define VBOXVDMACMD_DMA_PRESENT_BLT_MINSIZE() (VBOXVDMACMD_SIZE(VBOXVDMACMD_DMA_PRESENT_BLT))
4453#define VBOXVDMACMD_DMA_PRESENT_BLT_SIZE(_c) (VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[_c]))
4454
4455DECLINLINE(BOOLEAN) vboxWddmPixFormatConversionSupported(D3DDDIFORMAT From, D3DDDIFORMAT To)
4456{
4457 Assert(From != D3DDDIFMT_UNKNOWN);
4458 Assert(To != D3DDDIFMT_UNKNOWN);
4459 Assert(From == To);
4460 return From == To;
4461}
4462
4463NTSTATUS
4464APIENTRY
4465DxgkDdiUpdateOverlay(
4466 CONST HANDLE hOverlay,
4467 CONST DXGKARG_UPDATEOVERLAY *pUpdateOverlay)
4468{
4469 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4470
4471 NTSTATUS Status = STATUS_SUCCESS;
4472
4473#ifdef VBOX_WITH_VIDEOHWACCEL
4474 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4475 AssertPtr(pOverlay);
4476 int rc = vboxVhwaHlpOverlayUpdate(pOverlay, &pUpdateOverlay->OverlayInfo);
4477 AssertRC(rc);
4478 if (RT_FAILURE(rc))
4479 Status = STATUS_UNSUCCESSFUL;
4480#else
4481 RT_NOREF(hOverlay, pUpdateOverlay);
4482#endif
4483
4484 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4485 return Status;
4486}
4487
4488NTSTATUS
4489APIENTRY
4490DxgkDdiFlipOverlay(
4491 CONST HANDLE hOverlay,
4492 CONST DXGKARG_FLIPOVERLAY *pFlipOverlay)
4493{
4494 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4495
4496 NTSTATUS Status = STATUS_SUCCESS;
4497
4498#ifdef VBOX_WITH_VIDEOHWACCEL
4499 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4500 AssertPtr(pOverlay);
4501 int rc = vboxVhwaHlpOverlayFlip(pOverlay, pFlipOverlay);
4502 AssertRC(rc);
4503 if (RT_FAILURE(rc))
4504 Status = STATUS_UNSUCCESSFUL;
4505#else
4506 RT_NOREF(hOverlay, pFlipOverlay);
4507#endif
4508
4509 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4510
4511 return Status;
4512}
4513
4514NTSTATUS
4515APIENTRY
4516DxgkDdiDestroyOverlay(
4517 CONST HANDLE hOverlay)
4518{
4519 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4520
4521 NTSTATUS Status = STATUS_SUCCESS;
4522
4523#ifdef VBOX_WITH_VIDEOHWACCEL
4524 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4525 AssertPtr(pOverlay);
4526 int rc = vboxVhwaHlpOverlayDestroy(pOverlay);
4527 AssertRC(rc);
4528 if (RT_SUCCESS(rc))
4529 vboxWddmMemFree(pOverlay);
4530 else
4531 Status = STATUS_UNSUCCESSFUL;
4532#else
4533 RT_NOREF(hOverlay);
4534#endif
4535
4536 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4537
4538 return Status;
4539}
4540
4541/**
4542 * DxgkDdiCreateContext
4543 */
4544NTSTATUS
4545APIENTRY
4546DxgkDdiCreateContext(
4547 CONST HANDLE hDevice,
4548 DXGKARG_CREATECONTEXT *pCreateContext)
4549{
4550 /* DxgkDdiCreateContext should be made pageable */
4551 PAGED_CODE();
4552
4553 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4554
4555 vboxVDbgBreakFv();
4556
4557 if (pCreateContext->NodeOrdinal >= VBOXWDDM_NUM_NODES)
4558 {
4559 WARN(("Invalid NodeOrdinal (%d), expected to be less that (%d)\n", pCreateContext->NodeOrdinal, VBOXWDDM_NUM_NODES));
4560 return STATUS_INVALID_PARAMETER;
4561 }
4562
4563 NTSTATUS Status = STATUS_SUCCESS;
4564 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4565 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4566 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)vboxWddmMemAllocZero(sizeof (VBOXWDDM_CONTEXT));
4567 Assert(pContext);
4568 if (pContext)
4569 {
4570 pContext->pDevice = pDevice;
4571 pContext->hContext = pCreateContext->hContext;
4572 pContext->EngineAffinity = pCreateContext->EngineAffinity;
4573 pContext->NodeOrdinal = pCreateContext->NodeOrdinal;
4574 vboxVideoCmCtxInitEmpty(&pContext->CmContext);
4575 if (pCreateContext->Flags.SystemContext || pCreateContext->PrivateDriverDataSize == 0)
4576 {
4577 Assert(pCreateContext->PrivateDriverDataSize == 0);
4578 Assert(!pCreateContext->pPrivateDriverData);
4579 Assert(pCreateContext->Flags.Value <= 2); /* 2 is a GDI context in Win7 */
4580 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_SYSTEM;
4581
4582 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VBOX)
4583 {
4584 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
4585 {
4586 vboxWddmDisplaySettingsCheckPos(pDevExt, i);
4587 }
4588 }
4589 Status = STATUS_SUCCESS;
4590 }
4591 else
4592 {
4593 Assert(pCreateContext->Flags.Value == 0);
4594 Assert(pCreateContext->PrivateDriverDataSize == sizeof (VBOXWDDM_CREATECONTEXT_INFO));
4595 Assert(pCreateContext->pPrivateDriverData);
4596 if (pCreateContext->PrivateDriverDataSize == sizeof (VBOXWDDM_CREATECONTEXT_INFO))
4597 {
4598 PVBOXWDDM_CREATECONTEXT_INFO pInfo = (PVBOXWDDM_CREATECONTEXT_INFO)pCreateContext->pPrivateDriverData;
4599 switch (pInfo->enmType)
4600 {
4601 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE:
4602 {
4603 pContext->enmType = pInfo->enmType;
4604 ASMAtomicIncU32(&pDevExt->cContextsDispIfResize);
4605 break;
4606 }
4607 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS:
4608 {
4609 pContext->enmType = pInfo->enmType;
4610 Status = vboxVideoCmCtxAdd(&pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext, (HANDLE)pInfo->u.vbox.hUmEvent, pInfo->u.vbox.u64UmInfo);
4611 if (!NT_SUCCESS(Status))
4612 {
4613 WARN(("vboxVideoCmCtxAdd failed, Status 0x%x", Status));
4614 }
4615 break;
4616 }
4617#ifdef VBOX_WITH_VMSVGA
4618 case VBOXWDDM_CONTEXT_TYPE_GA_3D:
4619 {
4620 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_GA_3D;
4621 Status = GaContextCreate(pDevExt->pGa, pInfo, pContext);
4622 break;
4623 }
4624#endif
4625#ifdef VBOX_WITH_VMSVGA3D_DX
4626 case VBOXWDDM_CONTEXT_TYPE_VMSVGA_D3D:
4627 {
4628 /* VMSVGA_D3D context type shares some code with GA_3D, because both work with VMSVGA GPU. */
4629 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_VMSVGA_D3D;
4630 Status = GaContextCreate(pDevExt->pGa, pInfo, pContext);
4631 break;
4632 }
4633#endif
4634 default:
4635 {
4636 WARN(("unsupported context type %d", pInfo->enmType));
4637 Status = STATUS_INVALID_PARAMETER;
4638 break;
4639 }
4640 }
4641 }
4642 }
4643
4644 if (Status == STATUS_SUCCESS)
4645 {
4646 pCreateContext->hContext = pContext;
4647 pCreateContext->ContextInfo.DmaBufferSize = VBOXWDDM_C_DMA_BUFFER_SIZE;
4648 pCreateContext->ContextInfo.DmaBufferSegmentSet = 0;
4649 pCreateContext->ContextInfo.DmaBufferPrivateDataSize = VBOXWDDM_C_DMA_PRIVATEDATA_SIZE;
4650 pCreateContext->ContextInfo.AllocationListSize = VBOXWDDM_C_ALLOC_LIST_SIZE;
4651 pCreateContext->ContextInfo.PatchLocationListSize = VBOXWDDM_C_PATH_LOCATION_LIST_SIZE;
4652 //#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN7)
4653 //# error port to Win7 DDI
4654 // //pCreateContext->ContextInfo.DmaBufferAllocationGroup = ???;
4655 //#endif // DXGKDDI_INTERFACE_VERSION
4656 }
4657 else
4658 vboxWddmMemFree(pContext);
4659 }
4660 else
4661 Status = STATUS_NO_MEMORY;
4662
4663 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4664
4665 return Status;
4666}
4667
4668NTSTATUS
4669APIENTRY
4670DxgkDdiDestroyContext(
4671 CONST HANDLE hContext)
4672{
4673 LOGF(("ENTER, hContext(0x%x)", hContext));
4674 vboxVDbgBreakFv();
4675 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
4676 PVBOXMP_DEVEXT pDevExt = pContext->pDevice->pAdapter;
4677 NTSTATUS Status = STATUS_SUCCESS;
4678
4679 switch(pContext->enmType)
4680 {
4681 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE:
4682 {
4683 uint32_t cContexts = ASMAtomicDecU32(&pDevExt->cContextsDispIfResize);
4684 Assert(cContexts < UINT32_MAX/2);
4685 if (!cContexts)
4686 {
4687 if (pDevExt->fDisableTargetUpdate)
4688 {
4689 pDevExt->fDisableTargetUpdate = FALSE;
4690 vboxWddmGhDisplayCheckSetInfoEx(pDevExt, true);
4691 }
4692 }
4693 break;
4694 }
4695 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS:
4696 {
4697 Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext);
4698 if (!NT_SUCCESS(Status))
4699 WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status));
4700
4701 Assert(pContext->CmContext.pSession == NULL);
4702 break;
4703 }
4704#ifdef VBOX_WITH_VMSVGA
4705 case VBOXWDDM_CONTEXT_TYPE_GA_3D:
4706 {
4707 Status = GaContextDestroy(pDevExt->pGa, pContext);
4708 break;
4709 }
4710#endif
4711#ifdef VBOX_WITH_VMSVGA3D_DX
4712 case VBOXWDDM_CONTEXT_TYPE_VMSVGA_D3D:
4713 {
4714 Status = GaContextDestroy(pDevExt->pGa, pContext);
4715 break;
4716 }
4717#endif
4718 default:
4719 break;
4720 }
4721
4722 Status = vboxVideoAMgrCtxDestroy(&pContext->AllocContext);
4723 if (NT_SUCCESS(Status))
4724 {
4725 Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->CmMgr, &pContext->CmContext);
4726 if (NT_SUCCESS(Status))
4727 vboxWddmMemFree(pContext);
4728 else
4729 WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status));
4730 }
4731 else
4732 WARN(("vboxVideoAMgrCtxDestroy failed, Status 0x%x", Status));
4733
4734 LOGF(("LEAVE, hContext(0x%x)", hContext));
4735
4736 return Status;
4737}
4738
4739NTSTATUS
4740APIENTRY
4741DxgkDdiLinkDevice(
4742 __in CONST PDEVICE_OBJECT PhysicalDeviceObject,
4743 __in CONST PVOID MiniportDeviceContext,
4744 __inout PLINKED_DEVICE LinkedDevice
4745 )
4746{
4747 RT_NOREF(PhysicalDeviceObject, MiniportDeviceContext, LinkedDevice);
4748 LOGF(("ENTER, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
4749 vboxVDbgBreakFv();
4750 AssertBreakpoint();
4751 LOGF(("LEAVE, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
4752 return STATUS_NOT_IMPLEMENTED;
4753}
4754
4755NTSTATUS
4756APIENTRY
4757DxgkDdiSetDisplayPrivateDriverFormat(
4758 CONST HANDLE hAdapter,
4759 /*CONST*/ DXGKARG_SETDISPLAYPRIVATEDRIVERFORMAT* pSetDisplayPrivateDriverFormat
4760 )
4761{
4762 RT_NOREF(hAdapter, pSetDisplayPrivateDriverFormat);
4763 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4764 vboxVDbgBreakFv();
4765 AssertBreakpoint();
4766 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4767 return STATUS_SUCCESS;
4768}
4769
4770NTSTATUS APIENTRY CALLBACK DxgkDdiRestartFromTimeout(IN_CONST_HANDLE hAdapter)
4771{
4772 RT_NOREF(hAdapter);
4773 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4774 vboxVDbgBreakFv();
4775 AssertBreakpoint();
4776 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4777 return STATUS_SUCCESS;
4778}
4779
4780static NTSTATUS APIENTRY DxgkDdiQueryVidPnHWCapability(
4781 __in const HANDLE hAdapter,
4782 __inout DXGKARG_QUERYVIDPNHWCAPABILITY *pVidPnHWCaps
4783 )
4784{
4785 RT_NOREF(hAdapter);
4786 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4787 vboxVDbgBreakF();
4788 pVidPnHWCaps->VidPnHWCaps.DriverRotation = 0;
4789 pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0;
4790 pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0;
4791 pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 0;
4792 pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0;
4793 pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0;
4794 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4795 return STATUS_SUCCESS;
4796}
4797
4798static NTSTATUS APIENTRY DxgkDdiPresentDisplayOnly(
4799 _In_ const HANDLE hAdapter,
4800 _In_ const DXGKARG_PRESENT_DISPLAYONLY *pPresentDisplayOnly
4801 )
4802{
4803 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4804 vboxVDbgBreakFv();
4805
4806 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4807#ifdef VBOX_WITH_VMSVGA
4808 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4809 {
4810 return GaDxgkDdiPresentDisplayOnly(hAdapter, pPresentDisplayOnly);
4811 }
4812#endif
4813 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pPresentDisplayOnly->VidPnSourceId];
4814 Assert(pSource->AllocData.Addr.SegmentId == 1);
4815 VBOXWDDM_ALLOC_DATA SrcAllocData;
4816 SrcAllocData.SurfDesc.width = pPresentDisplayOnly->Pitch * pPresentDisplayOnly->BytesPerPixel;
4817 SrcAllocData.SurfDesc.height = ~0UL;
4818 switch (pPresentDisplayOnly->BytesPerPixel)
4819 {
4820 case 4:
4821 SrcAllocData.SurfDesc.format = D3DDDIFMT_A8R8G8B8;
4822 break;
4823 case 3:
4824 SrcAllocData.SurfDesc.format = D3DDDIFMT_R8G8B8;
4825 break;
4826 case 2:
4827 SrcAllocData.SurfDesc.format = D3DDDIFMT_R5G6B5;
4828 break;
4829 case 1:
4830 SrcAllocData.SurfDesc.format = D3DDDIFMT_P8;
4831 break;
4832 default:
4833 WARN(("Unknown format"));
4834 SrcAllocData.SurfDesc.format = D3DDDIFMT_UNKNOWN;
4835 break;
4836 }
4837 SrcAllocData.SurfDesc.bpp = pPresentDisplayOnly->BytesPerPixel >> 3;
4838 SrcAllocData.SurfDesc.pitch = pPresentDisplayOnly->Pitch;
4839 SrcAllocData.SurfDesc.depth = 1;
4840 SrcAllocData.SurfDesc.slicePitch = pPresentDisplayOnly->Pitch;
4841 SrcAllocData.SurfDesc.cbSize = ~0UL;
4842 SrcAllocData.Addr.SegmentId = 0;
4843 SrcAllocData.Addr.pvMem = pPresentDisplayOnly->pSource;
4844 SrcAllocData.hostID = 0;
4845
4846 RECT UpdateRect;
4847 RT_ZERO(UpdateRect);
4848 BOOLEAN bUpdateRectInited = FALSE;
4849
4850 for (UINT i = 0; i < pPresentDisplayOnly->NumMoves; ++i)
4851 {
4852 if (!bUpdateRectInited)
4853 {
4854 UpdateRect = pPresentDisplayOnly->pMoves[i].DestRect;
4855 bUpdateRectInited = TRUE;
4856 }
4857 else
4858 vboxWddmRectUnite(&UpdateRect, &pPresentDisplayOnly->pMoves[i].DestRect);
4859 vboxVdmaGgDmaBltPerform(pDevExt, &SrcAllocData, &pPresentDisplayOnly->pMoves[i].DestRect, &pSource->AllocData, &pPresentDisplayOnly->pMoves[i].DestRect);
4860 }
4861
4862 for (UINT i = 0; i < pPresentDisplayOnly->NumDirtyRects; ++i)
4863 {
4864 RECT *pDirtyRect = &pPresentDisplayOnly->pDirtyRect[i];
4865
4866 if (pDirtyRect->left >= pDirtyRect->right || pDirtyRect->top >= pDirtyRect->bottom)
4867 {
4868 WARN(("Wrong dirty rect (%d, %d)-(%d, %d)",
4869 pDirtyRect->left, pDirtyRect->top, pDirtyRect->right, pDirtyRect->bottom));
4870 continue;
4871 }
4872
4873 vboxVdmaGgDmaBltPerform(pDevExt, &SrcAllocData, pDirtyRect, &pSource->AllocData, pDirtyRect);
4874
4875 if (!bUpdateRectInited)
4876 {
4877 UpdateRect = *pDirtyRect;
4878 bUpdateRectInited = TRUE;
4879 }
4880 else
4881 vboxWddmRectUnite(&UpdateRect, pDirtyRect);
4882 }
4883
4884 if (bUpdateRectInited && pSource->bVisible)
4885 {
4886 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UpdateRect);
4887 }
4888
4889 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4890 return STATUS_SUCCESS;
4891}
4892
4893static NTSTATUS DxgkDdiStopDeviceAndReleasePostDisplayOwnership(
4894 _In_ PVOID MiniportDeviceContext,
4895 _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
4896 _Out_ PDXGK_DISPLAY_INFORMATION DisplayInfo
4897)
4898{
4899 RT_NOREF(MiniportDeviceContext, TargetId, DisplayInfo);
4900 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4901 vboxVDbgBreakFv();
4902 AssertBreakpoint();
4903 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4904 return STATUS_NOT_SUPPORTED;
4905}
4906
4907static NTSTATUS DxgkDdiSystemDisplayEnable(
4908 _In_ PVOID MiniportDeviceContext,
4909 _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
4910 _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
4911 _Out_ UINT *Width,
4912 _Out_ UINT *Height,
4913 _Out_ D3DDDIFORMAT *ColorFormat
4914 )
4915{
4916 RT_NOREF(MiniportDeviceContext, TargetId, Flags, Width, Height, ColorFormat);
4917 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4918 vboxVDbgBreakFv();
4919 AssertBreakpoint();
4920 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4921 return STATUS_NOT_SUPPORTED;
4922}
4923
4924static VOID DxgkDdiSystemDisplayWrite(
4925 _In_ PVOID MiniportDeviceContext,
4926 _In_ PVOID Source,
4927 _In_ UINT SourceWidth,
4928 _In_ UINT SourceHeight,
4929 _In_ UINT SourceStride,
4930 _In_ UINT PositionX,
4931 _In_ UINT PositionY
4932)
4933{
4934 RT_NOREF(MiniportDeviceContext, Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY);
4935 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4936 vboxVDbgBreakFv();
4937 AssertBreakpoint();
4938 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4939}
4940
4941static NTSTATUS DxgkDdiGetChildContainerId(
4942 _In_ PVOID MiniportDeviceContext,
4943 _In_ ULONG ChildUid,
4944 _Inout_ PDXGK_CHILD_CONTAINER_ID ContainerId
4945)
4946{
4947 RT_NOREF(MiniportDeviceContext, ChildUid, ContainerId);
4948 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4949 vboxVDbgBreakFv();
4950 AssertBreakpoint();
4951 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4952 return STATUS_SUCCESS;
4953}
4954
4955static NTSTATUS APIENTRY DxgkDdiSetPowerComponentFState(
4956 _In_ const HANDLE DriverContext,
4957 UINT ComponentIndex,
4958 UINT FState
4959)
4960{
4961 RT_NOREF(DriverContext, ComponentIndex, FState);
4962 LOGF(("ENTER, DriverContext(0x%x)", DriverContext));
4963 vboxVDbgBreakFv();
4964 AssertBreakpoint();
4965 LOGF(("LEAVE, DriverContext(0x%x)", DriverContext));
4966 return STATUS_SUCCESS;
4967}
4968
4969static NTSTATUS APIENTRY DxgkDdiPowerRuntimeControlRequest(
4970 _In_ const HANDLE DriverContext,
4971 _In_ LPCGUID PowerControlCode,
4972 _In_opt_ PVOID InBuffer,
4973 _In_ SIZE_T InBufferSize,
4974 _Out_opt_ PVOID OutBuffer,
4975 _In_ SIZE_T OutBufferSize,
4976 _Out_opt_ PSIZE_T BytesReturned
4977)
4978{
4979 RT_NOREF(DriverContext, PowerControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned);
4980 LOGF(("ENTER, DriverContext(0x%x)", DriverContext));
4981 vboxVDbgBreakFv();
4982 AssertBreakpoint();
4983 LOGF(("LEAVE, DriverContext(0x%x)", DriverContext));
4984 return STATUS_SUCCESS;
4985}
4986
4987static NTSTATUS DxgkDdiNotifySurpriseRemoval(
4988 _In_ PVOID MiniportDeviceContext,
4989 _In_ DXGK_SURPRISE_REMOVAL_TYPE RemovalType
4990 )
4991{
4992 RT_NOREF(MiniportDeviceContext, RemovalType);
4993 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4994 vboxVDbgBreakFv();
4995 AssertBreakpoint();
4996 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4997 return STATUS_SUCCESS;
4998}
4999
5000static BOOLEAN DxgkDdiInterruptRoutine(const PVOID MiniportDeviceContext,
5001 ULONG MessageNumber)
5002{
5003#ifdef VBOX_WITH_VMSVGA
5004 BOOLEAN const fVMSVGA = GaDxgkDdiInterruptRoutine(MiniportDeviceContext, MessageNumber);
5005#else
5006 BOOLEAN const fVMSVGA = FALSE;
5007#endif
5008
5009 BOOLEAN const fHGSMI = DxgkDdiInterruptRoutineLegacy(MiniportDeviceContext, MessageNumber);
5010 return fVMSVGA || fHGSMI;
5011}
5012
5013static VOID DxgkDdiDpcRoutine(const PVOID MiniportDeviceContext)
5014{
5015 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
5016
5017#ifdef VBOX_WITH_VMSVGA
5018 GaDxgkDdiDpcRoutine(MiniportDeviceContext);
5019#endif
5020 DxgkDdiDpcRoutineLegacy(MiniportDeviceContext);
5021
5022 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
5023}
5024
5025static NTSTATUS vboxWddmInitDisplayOnlyDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
5026{
5027 KMDDOD_INITIALIZATION_DATA DriverInitializationData = {'\0'};
5028
5029 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_WIN8;
5030
5031 DriverInitializationData.DxgkDdiAddDevice = DxgkDdiAddDevice;
5032 DriverInitializationData.DxgkDdiStartDevice = DxgkDdiStartDevice;
5033 DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice;
5034 DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice;
5035 DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest;
5036 DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine;
5037 DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine;
5038 DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations;
5039 DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus;
5040 DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor;
5041 DriverInitializationData.DxgkDdiSetPowerState = DxgkDdiSetPowerState;
5042 DriverInitializationData.DxgkDdiNotifyAcpiEvent = DxgkDdiNotifyAcpiEvent;
5043 DriverInitializationData.DxgkDdiResetDevice = DxgkDdiResetDevice;
5044 DriverInitializationData.DxgkDdiUnload = DxgkDdiUnload;
5045 DriverInitializationData.DxgkDdiQueryInterface = DxgkDdiQueryInterface;
5046 DriverInitializationData.DxgkDdiControlEtwLogging = DxgkDdiControlEtwLogging;
5047 DriverInitializationData.DxgkDdiQueryAdapterInfo = DxgkDdiQueryAdapterInfo;
5048 DriverInitializationData.DxgkDdiSetPalette = DxgkDdiSetPalette;
5049 DriverInitializationData.DxgkDdiSetPointerPosition = DxgkDdiSetPointerPosition;
5050 DriverInitializationData.DxgkDdiSetPointerShape = DxgkDdiSetPointerShape;
5051 DriverInitializationData.DxgkDdiEscape = DxgkDdiEscape;
5052 DriverInitializationData.DxgkDdiCollectDbgInfo = DxgkDdiCollectDbgInfo;
5053 DriverInitializationData.DxgkDdiIsSupportedVidPn = DxgkDdiIsSupportedVidPn;
5054 DriverInitializationData.DxgkDdiRecommendFunctionalVidPn = DxgkDdiRecommendFunctionalVidPn;
5055 DriverInitializationData.DxgkDdiEnumVidPnCofuncModality = DxgkDdiEnumVidPnCofuncModality;
5056 DriverInitializationData.DxgkDdiSetVidPnSourceVisibility = DxgkDdiSetVidPnSourceVisibility;
5057 DriverInitializationData.DxgkDdiCommitVidPn = DxgkDdiCommitVidPn;
5058 DriverInitializationData.DxgkDdiUpdateActiveVidPnPresentPath = DxgkDdiUpdateActiveVidPnPresentPath;
5059 DriverInitializationData.DxgkDdiRecommendMonitorModes = DxgkDdiRecommendMonitorModes;
5060 DriverInitializationData.DxgkDdiQueryVidPnHWCapability = DxgkDdiQueryVidPnHWCapability;
5061 DriverInitializationData.DxgkDdiPresentDisplayOnly = DxgkDdiPresentDisplayOnly;
5062 DriverInitializationData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = DxgkDdiStopDeviceAndReleasePostDisplayOwnership;
5063 DriverInitializationData.DxgkDdiSystemDisplayEnable = DxgkDdiSystemDisplayEnable;
5064 DriverInitializationData.DxgkDdiSystemDisplayWrite = DxgkDdiSystemDisplayWrite;
5065// DriverInitializationData.DxgkDdiGetChildContainerId = DxgkDdiGetChildContainerId;
5066// DriverInitializationData.DxgkDdiSetPowerComponentFState = DxgkDdiSetPowerComponentFState;
5067// DriverInitializationData.DxgkDdiPowerRuntimeControlRequest = DxgkDdiPowerRuntimeControlRequest;
5068// DriverInitializationData.DxgkDdiNotifySurpriseRemoval = DxgkDdiNotifySurpriseRemoval;
5069
5070 /* Display-only driver is not required to report VSYNC.
5071 * The Microsoft KMDOD driver sample does not implement DxgkDdiControlInterrupt and DxgkDdiGetScanLine.
5072 * The functions must be either both implemented or none implemented.
5073 * Windows 10 10586 guests had problems with VSYNC in display-only driver (#8228).
5074 * Therefore the driver does not implement DxgkDdiControlInterrupt and DxgkDdiGetScanLine.
5075 */
5076
5077 NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject,
5078 pRegistryPath,
5079 &DriverInitializationData);
5080 if (!NT_SUCCESS(Status))
5081 {
5082 WARN(("DxgkInitializeDisplayOnlyDriver failed! Status 0x%x", Status));
5083 }
5084 return Status;
5085}
5086
5087static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath, VBOXVIDEO_HWTYPE enmHwType)
5088{
5089 DRIVER_INITIALIZATION_DATA DriverInitializationData = {'\0'};
5090
5091 // Fill in the DriverInitializationData structure and call DxgkInitialize()
5092 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
5093 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_WIN8;
5094 else
5095 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_VISTA_SP1;
5096
5097 DriverInitializationData.DxgkDdiAddDevice = DxgkDdiAddDevice;
5098 DriverInitializationData.DxgkDdiStartDevice = DxgkDdiStartDevice;
5099 DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice;
5100 DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice;
5101 DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest;
5102 DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine;
5103 DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine;
5104
5105#ifdef VBOX_WITH_VMSVGA
5106 if (enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
5107 {
5108 DriverInitializationData.DxgkDdiPatch = GaDxgkDdiPatch;
5109 DriverInitializationData.DxgkDdiSubmitCommand = GaDxgkDdiSubmitCommand;
5110 DriverInitializationData.DxgkDdiPreemptCommand = GaDxgkDdiPreemptCommand;
5111 DriverInitializationData.DxgkDdiBuildPagingBuffer = GaDxgkDdiBuildPagingBuffer;
5112 DriverInitializationData.DxgkDdiQueryCurrentFence = GaDxgkDdiQueryCurrentFence;
5113 DriverInitializationData.DxgkDdiRender = GaDxgkDdiRender;
5114 DriverInitializationData.DxgkDdiPresent = SvgaDxgkDdiPresent;
5115 }
5116 else
5117#endif
5118 {
5119 RT_NOREF(enmHwType);
5120
5121 DriverInitializationData.DxgkDdiPatch = DxgkDdiPatchLegacy;
5122 DriverInitializationData.DxgkDdiSubmitCommand = DxgkDdiSubmitCommandLegacy;
5123 DriverInitializationData.DxgkDdiPreemptCommand = DxgkDdiPreemptCommandLegacy;
5124 DriverInitializationData.DxgkDdiBuildPagingBuffer = DxgkDdiBuildPagingBufferLegacy;
5125 DriverInitializationData.DxgkDdiQueryCurrentFence = DxgkDdiQueryCurrentFenceLegacy;
5126 DriverInitializationData.DxgkDdiRender = DxgkDdiRenderLegacy;
5127 DriverInitializationData.DxgkDdiPresent = DxgkDdiPresentLegacy;
5128 }
5129
5130 DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations;
5131 DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus;
5132 DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor;
5133 DriverInitializationData.DxgkDdiSetPowerState = DxgkDdiSetPowerState;
5134 DriverInitializationData.DxgkDdiNotifyAcpiEvent = DxgkDdiNotifyAcpiEvent;
5135 DriverInitializationData.DxgkDdiResetDevice = DxgkDdiResetDevice;
5136 DriverInitializationData.DxgkDdiUnload = DxgkDdiUnload;
5137 DriverInitializationData.DxgkDdiQueryInterface = DxgkDdiQueryInterface;
5138 DriverInitializationData.DxgkDdiControlEtwLogging = DxgkDdiControlEtwLogging;
5139
5140 DriverInitializationData.DxgkDdiQueryAdapterInfo = DxgkDdiQueryAdapterInfo;
5141 DriverInitializationData.DxgkDdiCreateDevice = DxgkDdiCreateDevice;
5142 DriverInitializationData.DxgkDdiCreateAllocation = DxgkDdiCreateAllocation;
5143 DriverInitializationData.DxgkDdiDestroyAllocation = DxgkDdiDestroyAllocation;
5144 DriverInitializationData.DxgkDdiDescribeAllocation = DxgkDdiDescribeAllocation;
5145 DriverInitializationData.DxgkDdiGetStandardAllocationDriverData = DxgkDdiGetStandardAllocationDriverData;
5146 DriverInitializationData.DxgkDdiAcquireSwizzlingRange = DxgkDdiAcquireSwizzlingRange;
5147 DriverInitializationData.DxgkDdiReleaseSwizzlingRange = DxgkDdiReleaseSwizzlingRange;
5148
5149 DriverInitializationData.DxgkDdiSetPalette = DxgkDdiSetPalette;
5150 DriverInitializationData.DxgkDdiSetPointerPosition = DxgkDdiSetPointerPosition;
5151 DriverInitializationData.DxgkDdiSetPointerShape = DxgkDdiSetPointerShape;
5152 DriverInitializationData.DxgkDdiResetFromTimeout = DxgkDdiResetFromTimeout;
5153 DriverInitializationData.DxgkDdiRestartFromTimeout = DxgkDdiRestartFromTimeout;
5154 DriverInitializationData.DxgkDdiEscape = DxgkDdiEscape;
5155 DriverInitializationData.DxgkDdiCollectDbgInfo = DxgkDdiCollectDbgInfo;
5156 DriverInitializationData.DxgkDdiIsSupportedVidPn = DxgkDdiIsSupportedVidPn;
5157 DriverInitializationData.DxgkDdiRecommendFunctionalVidPn = DxgkDdiRecommendFunctionalVidPn;
5158 DriverInitializationData.DxgkDdiEnumVidPnCofuncModality = DxgkDdiEnumVidPnCofuncModality;
5159 DriverInitializationData.DxgkDdiSetVidPnSourceAddress = DxgkDdiSetVidPnSourceAddress;
5160 DriverInitializationData.DxgkDdiSetVidPnSourceVisibility = DxgkDdiSetVidPnSourceVisibility;
5161 DriverInitializationData.DxgkDdiCommitVidPn = DxgkDdiCommitVidPn;
5162 DriverInitializationData.DxgkDdiUpdateActiveVidPnPresentPath = DxgkDdiUpdateActiveVidPnPresentPath;
5163 DriverInitializationData.DxgkDdiRecommendMonitorModes = DxgkDdiRecommendMonitorModes;
5164 DriverInitializationData.DxgkDdiRecommendVidPnTopology = DxgkDdiRecommendVidPnTopology;
5165 DriverInitializationData.DxgkDdiGetScanLine = DxgkDdiGetScanLine;
5166 DriverInitializationData.DxgkDdiStopCapture = DxgkDdiStopCapture;
5167 DriverInitializationData.DxgkDdiControlInterrupt = DxgkDdiControlInterrupt;
5168 DriverInitializationData.DxgkDdiCreateOverlay = DxgkDdiCreateOverlay;
5169
5170 DriverInitializationData.DxgkDdiDestroyDevice = DxgkDdiDestroyDevice;
5171 DriverInitializationData.DxgkDdiOpenAllocation = DxgkDdiOpenAllocation;
5172 DriverInitializationData.DxgkDdiCloseAllocation = DxgkDdiCloseAllocation;
5173
5174 DriverInitializationData.DxgkDdiUpdateOverlay = DxgkDdiUpdateOverlay;
5175 DriverInitializationData.DxgkDdiFlipOverlay = DxgkDdiFlipOverlay;
5176 DriverInitializationData.DxgkDdiDestroyOverlay = DxgkDdiDestroyOverlay;
5177
5178 DriverInitializationData.DxgkDdiCreateContext = DxgkDdiCreateContext;
5179 DriverInitializationData.DxgkDdiDestroyContext = DxgkDdiDestroyContext;
5180
5181 DriverInitializationData.DxgkDdiLinkDevice = NULL; //DxgkDdiLinkDevice;
5182 DriverInitializationData.DxgkDdiSetDisplayPrivateDriverFormat = DxgkDdiSetDisplayPrivateDriverFormat;
5183
5184 if (DriverInitializationData.Version >= DXGKDDI_INTERFACE_VERSION_WIN7)
5185 {
5186 DriverInitializationData.DxgkDdiQueryVidPnHWCapability = DxgkDdiQueryVidPnHWCapability;
5187 }
5188
5189 NTSTATUS Status = DxgkInitialize(pDriverObject,
5190 pRegistryPath,
5191 &DriverInitializationData);
5192 if (!NT_SUCCESS(Status))
5193 {
5194 WARN(("DxgkInitialize failed! Status 0x%x", Status));
5195 }
5196 return Status;
5197}
5198
5199NTSTATUS
5200DriverEntry(
5201 IN PDRIVER_OBJECT DriverObject,
5202 IN PUNICODE_STRING RegistryPath
5203 )
5204{
5205 PAGED_CODE();
5206
5207 vboxVDbgBreakFv();
5208
5209 int irc = RTR0Init(0);
5210 if (RT_FAILURE(irc))
5211 {
5212 RTLogBackdoorPrintf("VBoxWddm: RTR0Init failed: %Rrc!\n", irc);
5213 return STATUS_UNSUCCESSFUL;
5214 }
5215
5216#if 0//def DEBUG_misha
5217 RTLogGroupSettings(0, "+default.e.l.f.l2.l3");
5218#endif
5219
5220#ifdef DEBUG
5221#define VBOXWDDM_BUILD_TYPE "dbg"
5222#else
5223#define VBOXWDDM_BUILD_TYPE "rel"
5224#endif
5225
5226 LOGREL(("VBox WDDM Driver for Windows %s version %d.%d.%dr%d %s, %d bit; Built %s %s",
5227 VBoxQueryWinVersion(NULL) >= WINVERSION_8 ? "8+" : "Vista and 7",
5228 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
5229 VBOXWDDM_BUILD_TYPE,
5230 (sizeof (void*) << 3), __DATE__, __TIME__));
5231
5232 if ( !ARGUMENT_PRESENT(DriverObject)
5233 || !ARGUMENT_PRESENT(RegistryPath))
5234 return STATUS_INVALID_PARAMETER;
5235
5236 vboxWddmDrvCfgInit(RegistryPath);
5237
5238 ULONG major, minor, build;
5239 BOOLEAN fCheckedBuild = PsGetVersion(&major, &minor, &build, NULL); NOREF(fCheckedBuild);
5240 BOOLEAN f3DRequired = FALSE;
5241
5242 LOGREL(("OsVersion(%d, %d, %d)", major, minor, build));
5243
5244 NTSTATUS Status = STATUS_SUCCESS;
5245 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
5246 int rc = VbglR0InitClient();
5247 if (RT_SUCCESS(rc))
5248 {
5249 /* Check whether 3D is required by the guest. */
5250 if (major > 6)
5251 {
5252 /* Windows 10 and newer. */
5253 f3DRequired = TRUE;
5254 }
5255 else if (major == 6)
5256 {
5257 if (minor >= 2)
5258 {
5259 /* Windows 8, 8.1 and 10 preview. */
5260 f3DRequired = TRUE;
5261 }
5262 else
5263 {
5264 f3DRequired = FALSE;
5265 }
5266 }
5267 else
5268 {
5269 WARN(("Unsupported OLDER win version, ignore and assume 3D is NOT required"));
5270 f3DRequired = FALSE;
5271 }
5272
5273 LOG(("3D is %srequired!", f3DRequired? "": "NOT "));
5274
5275 /* Check whether 3D is provided by the host. */
5276 VBOXVIDEO_HWTYPE enmHwType = VBOXVIDEO_HWTYPE_VBOX;
5277 BOOL f3DSupported = FALSE;
5278
5279 if (VBoxVGACfgAvailable())
5280 {
5281 /* New configuration query interface is available. */
5282 uint32_t u32;
5283 if (VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VERSION, &u32, 0))
5284 {
5285 LOGREL(("WDDM: VGA configuration version %d", u32));
5286 }
5287
5288 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_3D, &u32, 0);
5289 f3DSupported = RT_BOOL(u32);
5290
5291 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VMSVGA, &u32, 0);
5292 if (u32)
5293 {
5294 enmHwType = VBOXVIDEO_HWTYPE_VMSVGA;
5295 }
5296
5297 BOOL fVGPU10 = FALSE;
5298 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VMSVGA_DX, &u32, 0);
5299 if (u32)
5300 {
5301 fVGPU10 = TRUE;
5302 }
5303 LOGREL(("WDDM: VGA configuration: 3D %d, hardware type %d, VGPU10 %d", f3DSupported, enmHwType, fVGPU10));
5304 if (!fVGPU10)
5305 f3DSupported = FALSE;
5306 }
5307
5308 if (enmHwType == VBOXVIDEO_HWTYPE_VBOX)
5309 {
5310 /* No 3D for legacy adapter. */
5311 f3DSupported = FALSE;
5312 }
5313 else if (enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
5314 {
5315 /* Nothing. */
5316 }
5317 else
5318 {
5319 /* No supported hardware, fallback to VBox 2D only. */
5320 enmHwType = VBOXVIDEO_HWTYPE_VBOX;
5321 f3DSupported = FALSE;
5322 }
5323
5324 LOGREL(("WDDM: 3D is %ssupported, hardware type %d", f3DSupported? "": "not ", enmHwType));
5325
5326 if (NT_SUCCESS(Status))
5327 {
5328 if (!f3DSupported)
5329 {
5330 /* No 3D support by the host. */
5331 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
5332 {
5333 /* Use display only driver for Win8+. */
5334 g_VBoxDisplayOnly = 1;
5335
5336 /* Black list some builds. */
5337 if (major == 6 && minor == 4 && build == 9841)
5338 {
5339 /* W10 Technical preview crashes with display-only driver. */
5340 LOGREL(("3D is NOT supported by the host, fallback to the system video driver."));
5341 Status = STATUS_UNSUCCESSFUL;
5342 }
5343 else
5344 {
5345 LOGREL(("3D is NOT supported by the host, falling back to display-only mode.."));
5346 }
5347 }
5348 else
5349 {
5350 if (f3DRequired)
5351 {
5352 LOGREL(("3D is NOT supported by the host, but is required for the current guest version using this driver.."));
5353 Status = STATUS_UNSUCCESSFUL;
5354 }
5355 else
5356 LOGREL(("3D is NOT supported by the host, but is NOT required for the current guest version using this driver, continuing with Disabled 3D.."));
5357 }
5358 }
5359 }
5360
5361 if (NT_SUCCESS(Status))
5362 {
5363 if (g_VBoxDisplayOnly)
5364 {
5365 Status = vboxWddmInitDisplayOnlyDriver(DriverObject, RegistryPath);
5366 }
5367 else
5368 {
5369 Status = vboxWddmInitFullGraphicsDriver(DriverObject, RegistryPath, enmHwType);
5370 }
5371
5372 if (NT_SUCCESS(Status))
5373 {
5374 /*
5375 * Successfully initialized the driver.
5376 */
5377 return Status;
5378 }
5379
5380 /*
5381 * Cleanup on failure.
5382 */
5383 }
5384 else
5385 LOGREL(("Aborting the video driver load due to 3D support missing"));
5386
5387 VbglR0TerminateClient();
5388 }
5389 else
5390 {
5391 WARN(("VbglR0InitClient failed, rc(%d)", rc));
5392 Status = STATUS_UNSUCCESSFUL;
5393 }
5394
5395 AssertRelease(!NT_SUCCESS(Status));
5396
5397 PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
5398 if (pLogger)
5399 {
5400 RTLogDestroy(pLogger);
5401 }
5402 pLogger = RTLogSetDefaultInstance(NULL);
5403 if (pLogger)
5404 {
5405 RTLogDestroy(pLogger);
5406 }
5407
5408 return Status;
5409}
Note: See TracBrowser for help on using the repository browser.

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