VirtualBox

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

Last change on this file since 105526 was 105526, checked in by vboxsync, 4 months ago

GA/Windows: New VBOXESC_RECONNECT_TARGETS instead of VBOXESC_CONFIGURETARGETS to forcibly reconnect a guest displays. bugref:10714

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