VirtualBox

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

Last change on this file since 105749 was 105749, checked in by vboxsync, 3 months ago

GA/Windows: Use two separate bitmasks for displays to enable and disable. bugref:10714

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