VirtualBox

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

Last change on this file since 82414 was 82414, checked in by vboxsync, 5 years ago

WDDM: introduce DXVA capability flag; log the adapter capabilities; log the build type

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

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