VirtualBox

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

Last change on this file since 85375 was 85375, checked in by vboxsync, 4 years ago

WDDM: tweaked miniport capabilities to be at Win7+ level (follow-up to r138962)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 185.9 KB
Line 
1/* $Id: VBoxMPWddm.cpp 85375 2020-07-17 15:49:44Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver
4 */
5
6/*
7 * Copyright (C) 2011-2020 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#include <iprt/utf16.h>
32
33#include <VBox/VBoxGuestLib.h>
34#include <VBox/VMMDev.h> /* for VMMDevVideoSetVisibleRegion */
35#include <VBoxVideo.h>
36#include <wingdi.h> /* needed for RGNDATA definition */
37#include <VBoxDisplay.h> /* this is from Additions/WINNT/include/ to include escape codes */
38#include <VBoxVideoVBE.h>
39#include <VBox/Version.h>
40
41#ifdef VBOX_WITH_MESA3D
42#include "gallium/VBoxMPGaWddm.h"
43#endif
44
45#ifdef DEBUG
46DWORD g_VBoxLogUm = VBOXWDDM_CFG_LOG_UM_BACKDOOR;
47#else
48DWORD g_VBoxLogUm = 0;
49#endif
50DWORD g_RefreshRate = 0;
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 == (unsigned)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 == (unsigned)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
1096 Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_READ, &hKey);
1097 if (!NT_SUCCESS(Status))
1098 {
1099 WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
1100 hKey = NULL;
1101 }
1102
1103
1104 if (hKey)
1105 {
1106 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, &dwVal);
1107 if (!NT_SUCCESS(Status))
1108 {
1109 LOG(("vboxWddmRegQueryValueDword failed, Status = 0x%x", Status));
1110 dwVal = VBOXWDDM_CFG_DRV_DEFAULT;
1111 }
1112 }
1113
1114 pDevExt->dwDrvCfgFlags = dwVal;
1115
1116 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1117 {
1118 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i];
1119 if (i == 0 || (pDevExt->dwDrvCfgFlags & VBOXWDDM_CFG_DRV_SECONDARY_TARGETS_CONNECTED) || !hKey)
1120 {
1121 pTarget->fConnected = true;
1122 pTarget->fConfigured = true;
1123 }
1124 else if (hKey)
1125 {
1126 WCHAR wszNameBuf[sizeof(VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX) / sizeof(WCHAR) + 32];
1127 RTUtf16Printf(wszNameBuf, RT_ELEMENTS(wszNameBuf), "%ls%u", VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX, i);
1128 Status = vboxWddmRegQueryValueDword(hKey, wszNameBuf, &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->PresentationCaps.AlignmentShift = 2;
1650 pCaps->PresentationCaps.MaxTextureWidthShift = 2; /* Up to 8196 */
1651 pCaps->PresentationCaps.MaxTextureHeightShift = 2; /* Up to 8196 */
1652 pCaps->MaxQueuedFlipOnVSync = 0; /* do we need it? */
1653 pCaps->FlipCaps.Value = 0;
1654 /* ? pCaps->FlipCaps.FlipOnVSyncWithNoWait = 1; */
1655 pCaps->SchedulingCaps.Value = 0;
1656 /* we might need it for Aero.
1657 * Setting this flag means we support DeviceContext, i.e.
1658 * DxgkDdiCreateContext and DxgkDdiDestroyContext
1659 */
1660 pCaps->SchedulingCaps.MultiEngineAware = 1;
1661 pCaps->MemoryManagementCaps.Value = 0;
1662 /** @todo this correlates with pCaps->SchedulingCaps.MultiEngineAware */
1663 pCaps->MemoryManagementCaps.PagingNode = 0;
1664 /** @todo this correlates with pCaps->SchedulingCaps.MultiEngineAware */
1665 pCaps->GpuEngineTopology.NbAsymetricProcessingNodes = VBOXWDDM_NUM_NODES;
1666#ifdef VBOX_WITH_MESA3D
1667 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
1668 {
1669 /* The Gallium node has NodeOrdinal == 0, because:
1670 * GDI context is created with it;
1671 * we generate commands for the context;
1672 * there seems to be no easy way to distinguish which node a fence was completed for.
1673 *
1674 * GDI context is used for example for copying between D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE
1675 * and D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE.
1676 */
1677 pCaps->GpuEngineTopology.NbAsymetricProcessingNodes = 1;
1678 }
1679#endif
1680
1681 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
1682 pCaps->WDDMVersion = DXGKDDI_WDDMv1_2;
1683 }
1684 else
1685 {
1686 pCaps->WDDMVersion = DXGKDDI_WDDMv1_2;
1687 }
1688 break;
1689 }
1690 case DXGKQAITYPE_QUERYSEGMENT:
1691 {
1692 if (!g_VBoxDisplayOnly)
1693 {
1694 /* no need for DXGK_QUERYSEGMENTIN as it contains AGP aperture info, which (AGP aperture) we do not support
1695 * DXGK_QUERYSEGMENTIN *pQsIn = (DXGK_QUERYSEGMENTIN*)pQueryAdapterInfo->pInputData; */
1696 DXGK_QUERYSEGMENTOUT *pQsOut = (DXGK_QUERYSEGMENTOUT*)pQueryAdapterInfo->pOutputData;
1697# define VBOXWDDM_SEGMENTS_COUNT 2
1698 if (!pQsOut->pSegmentDescriptor)
1699 {
1700 /* we are requested to provide the number of segments we support */
1701 pQsOut->NbSegment = VBOXWDDM_SEGMENTS_COUNT;
1702 }
1703 else if (pQsOut->NbSegment != VBOXWDDM_SEGMENTS_COUNT)
1704 {
1705 WARN(("NbSegment (%d) != 1", pQsOut->NbSegment));
1706 Status = STATUS_INVALID_PARAMETER;
1707 }
1708 else
1709 {
1710 DXGK_SEGMENTDESCRIPTOR* pDr = pQsOut->pSegmentDescriptor;
1711 /* we are requested to provide segment information */
1712 pDr->BaseAddress.QuadPart = 0;
1713 pDr->CpuTranslatedAddress = VBoxCommonFromDeviceExt(pDevExt)->phVRAM;
1714 /* make sure the size is page aligned */
1715 /** @todo need to setup VBVA buffers and adjust the mem size here */
1716 pDr->Size = vboxWddmVramCpuVisibleSegmentSize(pDevExt);
1717 pDr->NbOfBanks = 0;
1718 pDr->pBankRangeTable = 0;
1719 pDr->CommitLimit = pDr->Size;
1720 pDr->Flags.Value = 0;
1721 pDr->Flags.CpuVisible = 1;
1722
1723 ++pDr;
1724 /* create cpu-invisible segment of the same size */
1725 pDr->BaseAddress.QuadPart = 0;
1726 pDr->CpuTranslatedAddress.QuadPart = 0;
1727 /* make sure the size is page aligned */
1728 /** @todo need to setup VBVA buffers and adjust the mem size here */
1729 pDr->Size = vboxWddmVramCpuInvisibleSegmentSize(pDevExt);
1730 pDr->NbOfBanks = 0;
1731 pDr->pBankRangeTable = 0;
1732 pDr->CommitLimit = pDr->Size;
1733 pDr->Flags.Value = 0;
1734
1735 pQsOut->PagingBufferSegmentId = 0;
1736 pQsOut->PagingBufferSize = PAGE_SIZE;
1737 pQsOut->PagingBufferPrivateDataSize = PAGE_SIZE;
1738 }
1739 }
1740 else
1741 {
1742 WARN(("unsupported Type (%d)", pQueryAdapterInfo->Type));
1743 Status = STATUS_NOT_SUPPORTED;
1744 }
1745
1746 break;
1747 }
1748 case DXGKQAITYPE_UMDRIVERPRIVATE:
1749 if (!g_VBoxDisplayOnly)
1750 {
1751 if (pQueryAdapterInfo->OutputDataSize >= sizeof(VBOXWDDM_QAI))
1752 {
1753 VBOXWDDM_QAI *pQAI = (VBOXWDDM_QAI *)pQueryAdapterInfo->pOutputData;
1754 memset(pQAI, 0, sizeof(VBOXWDDM_QAI));
1755
1756 pQAI->u32Version = VBOXVIDEOIF_VERSION;
1757 pQAI->enmHwType = pDevExt->enmHwType;
1758 pQAI->u32AdapterCaps = pDevExt->f3DEnabled ? VBOXWDDM_QAI_CAP_3D : 0;
1759 pQAI->u32AdapterCaps |= VBOXWDDM_QAI_CAP_DXVA; /** @todo Fetch from registry. */
1760 if (VBoxQueryWinVersion(NULL) >= WINVERSION_7)
1761 {
1762 pQAI->u32AdapterCaps |= VBOXWDDM_QAI_CAP_WIN7;
1763 // pQAI->u32AdapterCaps |= VBOXWDDM_QAI_CAP_DXVAHD; /** @todo Fetch from registry. */
1764 }
1765
1766 static int cLoggedCaps = 0;
1767 if (cLoggedCaps < 1)
1768 {
1769 ++cLoggedCaps;
1770 LOGREL_EXACT(("WDDM: adapter capabilities 0x%08X\n", pQAI->u32AdapterCaps));
1771 }
1772
1773 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VBOX)
1774 {
1775 pQAI->u.vbox.u32VBox3DCaps = 0;
1776 }
1777#ifdef VBOX_WITH_MESA3D
1778 else if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
1779 GaQueryInfo(pDevExt->pGa, pDevExt->enmHwType, &pQAI->u.vmsvga.HWInfo);
1780#endif
1781
1782#ifdef VBOX_WITH_VIDEOHWACCEL
1783 pQAI->cInfos = VBoxCommonFromDeviceExt(pDevExt)->cDisplays;
1784 for (uint32_t i = 0; i < pQAI->cInfos; ++i)
1785 {
1786 pQAI->aInfos[i] = pDevExt->aSources[i].Vhwa.Settings;
1787 }
1788#endif
1789 }
1790 else
1791 {
1792 WARN(("incorrect buffer size %d, expected %d", pQueryAdapterInfo->OutputDataSize, sizeof(VBOXWDDM_QAI)));
1793 Status = STATUS_BUFFER_TOO_SMALL;
1794 }
1795 }
1796 else
1797 {
1798 WARN(("unsupported Type (%d)", pQueryAdapterInfo->Type));
1799 Status = STATUS_NOT_SUPPORTED;
1800 }
1801 break;
1802
1803 case DXGKQAITYPE_QUERYSEGMENT3:
1804 LOGREL(("DXGKQAITYPE_QUERYSEGMENT3 treating as unsupported!"));
1805 Status = STATUS_NOT_SUPPORTED;
1806 break;
1807
1808 default:
1809 WARN(("unsupported Type (%d)", pQueryAdapterInfo->Type));
1810 Status = STATUS_NOT_SUPPORTED;
1811 break;
1812 }
1813 LOGF(("LEAVE, context(0x%x), Status(0x%x)", hAdapter, Status));
1814 return Status;
1815}
1816
1817/**
1818 * DxgkDdiCreateDevice
1819 */
1820NTSTATUS APIENTRY DxgkDdiCreateDevice(
1821 CONST HANDLE hAdapter,
1822 DXGKARG_CREATEDEVICE* pCreateDevice)
1823{
1824 /* DxgkDdiCreateDevice should be made pageable. */
1825 PAGED_CODE();
1826
1827 LOGF(("ENTER, context(0x%x)", hAdapter));
1828 NTSTATUS Status = STATUS_SUCCESS;
1829 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
1830
1831 vboxVDbgBreakFv();
1832
1833 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)vboxWddmMemAllocZero(sizeof (VBOXWDDM_DEVICE));
1834 if (!pDevice)
1835 {
1836 WARN(("vboxWddmMemAllocZero failed for WDDM device structure"));
1837 return STATUS_NO_MEMORY;
1838 }
1839
1840 pDevice->pAdapter = pDevExt;
1841 pDevice->hDevice = pCreateDevice->hDevice;
1842
1843 pCreateDevice->hDevice = pDevice;
1844 if (pCreateDevice->Flags.SystemDevice)
1845 pDevice->enmType = VBOXWDDM_DEVICE_TYPE_SYSTEM;
1846
1847 pCreateDevice->pInfo = NULL;
1848
1849#ifdef VBOX_WITH_MESA3D
1850 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
1851 {
1852 Status = GaDeviceCreate(pDevExt->pGa, pDevice);
1853 if (Status != STATUS_SUCCESS)
1854 {
1855 vboxWddmMemFree(pDevice);
1856 }
1857 }
1858#endif
1859
1860 LOGF(("LEAVE, context(0x%x), Status(0x%x)", hAdapter, Status));
1861
1862 return Status;
1863}
1864
1865PVBOXWDDM_RESOURCE vboxWddmResourceCreate(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_RCINFO pRcInfo)
1866{
1867 RT_NOREF(pDevExt);
1868 PVBOXWDDM_RESOURCE pResource = (PVBOXWDDM_RESOURCE)vboxWddmMemAllocZero(RT_UOFFSETOF_DYN(VBOXWDDM_RESOURCE,
1869 aAllocations[pRcInfo->cAllocInfos]));
1870 if (!pResource)
1871 {
1872 AssertFailed();
1873 return NULL;
1874 }
1875 pResource->cRefs = 1;
1876 pResource->cAllocations = pRcInfo->cAllocInfos;
1877 pResource->fFlags = pRcInfo->fFlags;
1878 pResource->RcDesc = pRcInfo->RcDesc;
1879 return pResource;
1880}
1881
1882VOID vboxWddmResourceRetain(PVBOXWDDM_RESOURCE pResource)
1883{
1884 ASMAtomicIncU32(&pResource->cRefs);
1885}
1886
1887static VOID vboxWddmResourceDestroy(PVBOXWDDM_RESOURCE pResource)
1888{
1889 vboxWddmMemFree(pResource);
1890}
1891
1892VOID vboxWddmResourceWaitDereference(PVBOXWDDM_RESOURCE pResource)
1893{
1894 vboxWddmCounterU32Wait(&pResource->cRefs, 1);
1895}
1896
1897VOID vboxWddmResourceRelease(PVBOXWDDM_RESOURCE pResource)
1898{
1899 uint32_t cRefs = ASMAtomicDecU32(&pResource->cRefs);
1900 Assert(cRefs < UINT32_MAX/2);
1901 if (!cRefs)
1902 {
1903 vboxWddmResourceDestroy(pResource);
1904 }
1905}
1906
1907void vboxWddmAllocationDeleteFromResource(PVBOXWDDM_RESOURCE pResource, PVBOXWDDM_ALLOCATION pAllocation)
1908{
1909 Assert(pAllocation->pResource == pResource);
1910 if (pResource)
1911 {
1912 Assert(&pResource->aAllocations[pAllocation->iIndex] == pAllocation);
1913 vboxWddmResourceRelease(pResource);
1914 }
1915 else
1916 {
1917 vboxWddmMemFree(pAllocation);
1918 }
1919}
1920
1921VOID vboxWddmAllocationCleanupAssignment(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAllocation)
1922{
1923 switch (pAllocation->enmType)
1924 {
1925 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE:
1926 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
1927 {
1928 if (pAllocation->bAssigned)
1929 {
1930 /** @todo do we need to notify host? */
1931 vboxWddmAssignPrimary(&pDevExt->aSources[pAllocation->AllocData.SurfDesc.VidPnSourceId], NULL, pAllocation->AllocData.SurfDesc.VidPnSourceId);
1932 }
1933 break;
1934 }
1935 default:
1936 break;
1937 }
1938}
1939
1940VOID vboxWddmAllocationCleanup(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAllocation)
1941{
1942 RT_NOREF(pDevExt);
1943 switch (pAllocation->enmType)
1944 {
1945 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE:
1946 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
1947 {
1948#if 0
1949 if (pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC)
1950 {
1951 if (pAllocation->hSharedHandle)
1952 {
1953 vboxShRcTreeRemove(pDevExt, pAllocation);
1954 }
1955 }
1956#endif
1957 break;
1958 }
1959 case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER:
1960 {
1961 break;
1962 }
1963 default:
1964 break;
1965 }
1966}
1967
1968VOID vboxWddmAllocationDestroy(PVBOXWDDM_ALLOCATION pAllocation)
1969{
1970 PAGED_CODE();
1971
1972 vboxWddmAllocationDeleteFromResource(pAllocation->pResource, pAllocation);
1973}
1974
1975PVBOXWDDM_ALLOCATION vboxWddmAllocationCreateFromResource(PVBOXWDDM_RESOURCE pResource, uint32_t iIndex)
1976{
1977 PVBOXWDDM_ALLOCATION pAllocation = NULL;
1978 if (pResource)
1979 {
1980 Assert(iIndex < pResource->cAllocations);
1981 if (iIndex < pResource->cAllocations)
1982 {
1983 pAllocation = &pResource->aAllocations[iIndex];
1984 memset(pAllocation, 0, sizeof (VBOXWDDM_ALLOCATION));
1985 }
1986 vboxWddmResourceRetain(pResource);
1987 }
1988 else
1989 pAllocation = (PVBOXWDDM_ALLOCATION)vboxWddmMemAllocZero(sizeof (VBOXWDDM_ALLOCATION));
1990
1991 if (pAllocation)
1992 {
1993 if (pResource)
1994 {
1995 pAllocation->pResource = pResource;
1996 pAllocation->iIndex = iIndex;
1997 }
1998 }
1999
2000 return pAllocation;
2001}
2002
2003NTSTATUS vboxWddmAllocationCreate(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_RESOURCE pResource, uint32_t iIndex, DXGK_ALLOCATIONINFO* pAllocationInfo)
2004{
2005 PAGED_CODE();
2006
2007 NTSTATUS Status = STATUS_SUCCESS;
2008
2009 Assert(pAllocationInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_ALLOCINFO));
2010 if (pAllocationInfo->PrivateDriverDataSize >= sizeof (VBOXWDDM_ALLOCINFO))
2011 {
2012 PVBOXWDDM_ALLOCINFO pAllocInfo = (PVBOXWDDM_ALLOCINFO)pAllocationInfo->pPrivateDriverData;
2013 PVBOXWDDM_ALLOCATION pAllocation = vboxWddmAllocationCreateFromResource(pResource, iIndex);
2014 Assert(pAllocation);
2015 if (pAllocation)
2016 {
2017 pAllocationInfo->pPrivateDriverData = NULL;
2018 pAllocationInfo->PrivateDriverDataSize = 0;
2019 pAllocationInfo->Alignment = 0;
2020 pAllocationInfo->PitchAlignedSize = 0;
2021 pAllocationInfo->HintedBank.Value = 0;
2022 pAllocationInfo->PreferredSegment.Value = 0;
2023 pAllocationInfo->SupportedReadSegmentSet = 1;
2024 pAllocationInfo->SupportedWriteSegmentSet = 1;
2025 pAllocationInfo->EvictionSegmentSet = 0;
2026 pAllocationInfo->MaximumRenamingListLength = 0;
2027 pAllocationInfo->hAllocation = pAllocation;
2028 pAllocationInfo->Flags.Value = 0;
2029 pAllocationInfo->pAllocationUsageHint = NULL;
2030 pAllocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_NORMAL;
2031
2032 pAllocation->enmType = pAllocInfo->enmType;
2033 pAllocation->AllocData.Addr.SegmentId = 0;
2034 pAllocation->AllocData.Addr.offVram = VBOXVIDEOOFFSET_VOID;
2035 pAllocation->bVisible = FALSE;
2036 pAllocation->bAssigned = FALSE;
2037 KeInitializeSpinLock(&pAllocation->OpenLock);
2038 InitializeListHead(&pAllocation->OpenList);
2039
2040 switch (pAllocInfo->enmType)
2041 {
2042 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE:
2043 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
2044 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE:
2045 case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE:
2046 {
2047 pAllocation->fRcFlags = pAllocInfo->fFlags;
2048 pAllocation->AllocData.SurfDesc = pAllocInfo->SurfDesc;
2049 pAllocation->AllocData.hostID = pAllocInfo->hostID;
2050
2051 pAllocationInfo->Size = pAllocInfo->SurfDesc.cbSize;
2052
2053 switch (pAllocInfo->enmType)
2054 {
2055 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE:
2056 break;
2057 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
2058#ifdef VBOX_WITH_VIDEOHWACCEL
2059 if (pAllocInfo->fFlags.Overlay)
2060 {
2061 /* actually we can not "properly" issue create overlay commands to the host here
2062 * because we do not know source VidPn id here, i.e.
2063 * the primary which is supposed to be overlayed,
2064 * however we need to get some info like pitch & size from the host here */
2065 int rc = vboxVhwaHlpGetSurfInfo(pDevExt, pAllocation);
2066 AssertRC(rc);
2067 if (RT_SUCCESS(rc))
2068 {
2069 pAllocationInfo->Flags.Overlay = 1;
2070 pAllocationInfo->Flags.CpuVisible = 1;
2071 pAllocationInfo->Size = pAllocation->AllocData.SurfDesc.cbSize;
2072
2073 pAllocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_HIGH;
2074 }
2075 else
2076 Status = STATUS_UNSUCCESSFUL;
2077 }
2078 else
2079#endif
2080 {
2081 RT_NOREF(pDevExt);
2082
2083 Assert(pAllocation->AllocData.SurfDesc.bpp);
2084 Assert(pAllocation->AllocData.SurfDesc.pitch);
2085 Assert(pAllocation->AllocData.SurfDesc.cbSize);
2086
2087 /*
2088 * Mark the allocation as visible to the CPU so we can
2089 * lock it in the user mode driver for SYSTEM pool allocations.
2090 * See @bugref{8040} for further information.
2091 */
2092 if (!pAllocInfo->fFlags.SharedResource && !pAllocInfo->hostID)
2093 pAllocationInfo->Flags.CpuVisible = 1;
2094
2095 if (pAllocInfo->fFlags.SharedResource)
2096 {
2097 pAllocation->hSharedHandle = (HANDLE)pAllocInfo->hSharedHandle;
2098#if 0
2099 if (pAllocation->hSharedHandle)
2100 {
2101 vboxShRcTreePut(pDevExt, pAllocation);
2102 }
2103#endif
2104 }
2105
2106#if 0
2107 /* Allocation from the CPU invisible second segment does not
2108 * work apparently and actually fails on Vista.
2109 *
2110 * @todo Find out what exactly is wrong.
2111 */
2112// if (pAllocInfo->hostID)
2113 {
2114 pAllocationInfo->SupportedReadSegmentSet = 2;
2115 pAllocationInfo->SupportedWriteSegmentSet = 2;
2116 }
2117#endif
2118 }
2119 break;
2120 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE:
2121 case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE:
2122 pAllocationInfo->Flags.CpuVisible = 1;
2123 break;
2124 default: AssertFailedBreak(); /* Shut up MSC.*/
2125 }
2126
2127 if (Status == STATUS_SUCCESS)
2128 {
2129 pAllocation->UsageHint.Version = 0;
2130 pAllocation->UsageHint.v1.Flags.Value = 0;
2131 pAllocation->UsageHint.v1.Format = pAllocInfo->SurfDesc.format;
2132 pAllocation->UsageHint.v1.SwizzledFormat = 0;
2133 pAllocation->UsageHint.v1.ByteOffset = 0;
2134 pAllocation->UsageHint.v1.Width = pAllocation->AllocData.SurfDesc.width;
2135 pAllocation->UsageHint.v1.Height = pAllocation->AllocData.SurfDesc.height;
2136 pAllocation->UsageHint.v1.Pitch = pAllocation->AllocData.SurfDesc.pitch;
2137 pAllocation->UsageHint.v1.Depth = 0;
2138 pAllocation->UsageHint.v1.SlicePitch = 0;
2139
2140 Assert(!pAllocationInfo->pAllocationUsageHint);
2141 pAllocationInfo->pAllocationUsageHint = &pAllocation->UsageHint;
2142 }
2143
2144 break;
2145 }
2146 case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER:
2147 {
2148 pAllocationInfo->Size = pAllocInfo->cbBuffer;
2149 pAllocation->fUhgsmiType = pAllocInfo->fUhgsmiType;
2150 pAllocation->AllocData.SurfDesc.cbSize = pAllocInfo->cbBuffer;
2151 pAllocationInfo->Flags.CpuVisible = 1;
2152// pAllocationInfo->Flags.SynchronousPaging = 1;
2153 pAllocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_MAXIMUM;
2154 break;
2155 }
2156
2157 default:
2158 LOGREL(("ERROR: invalid alloc info type(%d)", pAllocInfo->enmType));
2159 AssertBreakpoint();
2160 Status = STATUS_INVALID_PARAMETER;
2161 break;
2162
2163 }
2164
2165 if (Status != STATUS_SUCCESS)
2166 vboxWddmAllocationDeleteFromResource(pResource, pAllocation);
2167 }
2168 else
2169 {
2170 LOGREL(("ERROR: failed to create allocation description"));
2171 Status = STATUS_NO_MEMORY;
2172 }
2173
2174 }
2175 else
2176 {
2177 LOGREL(("ERROR: PrivateDriverDataSize(%d) less than header size(%d)", pAllocationInfo->PrivateDriverDataSize, sizeof (VBOXWDDM_ALLOCINFO)));
2178 Status = STATUS_INVALID_PARAMETER;
2179 }
2180
2181 return Status;
2182}
2183
2184NTSTATUS APIENTRY DxgkDdiCreateAllocation(
2185 CONST HANDLE hAdapter,
2186 DXGKARG_CREATEALLOCATION* pCreateAllocation)
2187{
2188 /* DxgkDdiCreateAllocation should be made pageable. */
2189 PAGED_CODE();
2190
2191 LOGF(("ENTER, context(0x%x)", hAdapter));
2192
2193 vboxVDbgBreakFv();
2194
2195 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
2196 NTSTATUS Status = STATUS_SUCCESS;
2197 PVBOXWDDM_RESOURCE pResource = NULL;
2198
2199 if (pCreateAllocation->PrivateDriverDataSize)
2200 {
2201 Assert(pCreateAllocation->PrivateDriverDataSize == sizeof (VBOXWDDM_RCINFO));
2202 Assert(pCreateAllocation->pPrivateDriverData);
2203 if (pCreateAllocation->PrivateDriverDataSize < sizeof (VBOXWDDM_RCINFO))
2204 {
2205 WARN(("invalid private data size (%d)", pCreateAllocation->PrivateDriverDataSize));
2206 return STATUS_INVALID_PARAMETER;
2207 }
2208
2209 PVBOXWDDM_RCINFO pRcInfo = (PVBOXWDDM_RCINFO)pCreateAllocation->pPrivateDriverData;
2210// Assert(pRcInfo->RcDesc.VidPnSourceId < VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
2211 if (pRcInfo->cAllocInfos != pCreateAllocation->NumAllocations)
2212 {
2213 WARN(("invalid number of allocations passed in, (%d), expected (%d)", pRcInfo->cAllocInfos, pCreateAllocation->NumAllocations));
2214 return STATUS_INVALID_PARAMETER;
2215 }
2216
2217 /* a check to ensure we do not get the allocation size which is too big to overflow the 32bit value */
2218 if (VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXWDDM_RESOURCE, aAllocations) < pRcInfo->cAllocInfos)
2219 {
2220 WARN(("number of allocations passed too big (%d), max is (%d)", pRcInfo->cAllocInfos, VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXWDDM_RESOURCE, aAllocations)));
2221 return STATUS_INVALID_PARAMETER;
2222 }
2223
2224 pResource = (PVBOXWDDM_RESOURCE)vboxWddmMemAllocZero(RT_UOFFSETOF_DYN(VBOXWDDM_RESOURCE, aAllocations[pRcInfo->cAllocInfos]));
2225 if (!pResource)
2226 {
2227 WARN(("vboxWddmMemAllocZero failed for (%d) allocations", pRcInfo->cAllocInfos));
2228 return STATUS_NO_MEMORY;
2229 }
2230
2231 pResource->cRefs = 1;
2232 pResource->cAllocations = pRcInfo->cAllocInfos;
2233 pResource->fFlags = pRcInfo->fFlags;
2234 pResource->RcDesc = pRcInfo->RcDesc;
2235 }
2236
2237
2238 for (UINT i = 0; i < pCreateAllocation->NumAllocations; ++i)
2239 {
2240 Status = vboxWddmAllocationCreate(pDevExt, pResource, i, &pCreateAllocation->pAllocationInfo[i]);
2241 if (Status != STATUS_SUCCESS)
2242 {
2243 WARN(("vboxWddmAllocationCreate(%d) failed, Status(0x%x)", i, Status));
2244 /* note: i-th allocation is expected to be cleared in a fail handling code above */
2245 for (UINT j = 0; j < i; ++j)
2246 {
2247 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pCreateAllocation->pAllocationInfo[j].hAllocation;
2248 vboxWddmAllocationCleanup(pDevExt, pAllocation);
2249 vboxWddmAllocationDestroy(pAllocation);
2250 }
2251 break;
2252 }
2253 }
2254
2255 if (Status == STATUS_SUCCESS)
2256 {
2257 pCreateAllocation->hResource = pResource;
2258 }
2259 else
2260 {
2261 if (pResource)
2262 vboxWddmResourceRelease(pResource);
2263 }
2264
2265 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
2266
2267 return Status;
2268}
2269
2270NTSTATUS
2271APIENTRY
2272DxgkDdiDestroyAllocation(
2273 CONST HANDLE hAdapter,
2274 CONST DXGKARG_DESTROYALLOCATION* pDestroyAllocation)
2275{
2276 /* DxgkDdiDestroyAllocation should be made pageable. */
2277 PAGED_CODE();
2278
2279 LOGF(("ENTER, context(0x%x)", hAdapter));
2280
2281 vboxVDbgBreakFv();
2282
2283 NTSTATUS Status = STATUS_SUCCESS;
2284
2285 PVBOXWDDM_RESOURCE pRc = (PVBOXWDDM_RESOURCE)pDestroyAllocation->hResource;
2286 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
2287
2288 if (pRc)
2289 {
2290 Assert(pRc->cAllocations == pDestroyAllocation->NumAllocations);
2291 }
2292
2293 for (UINT i = 0; i < pDestroyAllocation->NumAllocations; ++i)
2294 {
2295 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pDestroyAllocation->pAllocationList[i];
2296 Assert(pAlloc->pResource == pRc);
2297 vboxWddmAllocationCleanupAssignment(pDevExt, pAlloc);
2298 /* wait for all current allocation-related ops are completed */
2299 vboxWddmAllocationCleanup(pDevExt, pAlloc);
2300 vboxWddmAllocationDestroy(pAlloc);
2301 }
2302
2303 if (pRc)
2304 {
2305 /* wait for all current resource-related ops are completed */
2306 vboxWddmResourceWaitDereference(pRc);
2307 vboxWddmResourceRelease(pRc);
2308 }
2309
2310 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
2311
2312 return Status;
2313}
2314
2315/**
2316 * DxgkDdiDescribeAllocation
2317 */
2318NTSTATUS
2319APIENTRY
2320DxgkDdiDescribeAllocation(
2321 CONST HANDLE hAdapter,
2322 DXGKARG_DESCRIBEALLOCATION* pDescribeAllocation)
2323{
2324 RT_NOREF(hAdapter);
2325// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2326
2327 vboxVDbgBreakFv();
2328
2329 PVBOXWDDM_ALLOCATION pAllocation = (PVBOXWDDM_ALLOCATION)pDescribeAllocation->hAllocation;
2330 pDescribeAllocation->Width = pAllocation->AllocData.SurfDesc.width;
2331 pDescribeAllocation->Height = pAllocation->AllocData.SurfDesc.height;
2332 pDescribeAllocation->Format = pAllocation->AllocData.SurfDesc.format;
2333 memset (&pDescribeAllocation->MultisampleMethod, 0, sizeof (pDescribeAllocation->MultisampleMethod));
2334 pDescribeAllocation->RefreshRate.Numerator = g_RefreshRate * 1000;
2335 pDescribeAllocation->RefreshRate.Denominator = 1000;
2336 pDescribeAllocation->PrivateDriverFormatAttribute = 0;
2337
2338// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2339
2340 return STATUS_SUCCESS;
2341}
2342
2343/**
2344 * DxgkDdiGetStandardAllocationDriverData
2345 */
2346NTSTATUS
2347APIENTRY
2348DxgkDdiGetStandardAllocationDriverData(
2349 CONST HANDLE hAdapter,
2350 DXGKARG_GETSTANDARDALLOCATIONDRIVERDATA* pGetStandardAllocationDriverData)
2351{
2352 RT_NOREF(hAdapter);
2353 /* DxgkDdiGetStandardAllocationDriverData should be made pageable. */
2354 PAGED_CODE();
2355
2356 LOGF(("ENTER, context(0x%x)", hAdapter));
2357
2358 vboxVDbgBreakFv();
2359
2360 NTSTATUS Status = STATUS_SUCCESS;
2361 PVBOXWDDM_ALLOCINFO pAllocInfo = NULL;
2362
2363 switch (pGetStandardAllocationDriverData->StandardAllocationType)
2364 {
2365 case D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE:
2366 {
2367 LOGF(("D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE"));
2368 if(pGetStandardAllocationDriverData->pAllocationPrivateDriverData)
2369 {
2370 pAllocInfo = (PVBOXWDDM_ALLOCINFO)pGetStandardAllocationDriverData->pAllocationPrivateDriverData;
2371 memset (pAllocInfo, 0, sizeof (VBOXWDDM_ALLOCINFO));
2372 pAllocInfo->enmType = VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE;
2373 pAllocInfo->SurfDesc.width = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Width;
2374 pAllocInfo->SurfDesc.height = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Height;
2375 pAllocInfo->SurfDesc.format = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Format;
2376 pAllocInfo->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pAllocInfo->SurfDesc.format);
2377 pAllocInfo->SurfDesc.pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->Width, pAllocInfo->SurfDesc.format);
2378 pAllocInfo->SurfDesc.cbSize = vboxWddmCalcSize(pAllocInfo->SurfDesc.pitch, pAllocInfo->SurfDesc.height, pAllocInfo->SurfDesc.format);
2379 pAllocInfo->SurfDesc.depth = 0;
2380 pAllocInfo->SurfDesc.slicePitch = 0;
2381 pAllocInfo->SurfDesc.RefreshRate = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->RefreshRate;
2382 pAllocInfo->SurfDesc.VidPnSourceId = pGetStandardAllocationDriverData->pCreateSharedPrimarySurfaceData->VidPnSourceId;
2383 }
2384 pGetStandardAllocationDriverData->AllocationPrivateDriverDataSize = sizeof (VBOXWDDM_ALLOCINFO);
2385
2386 pGetStandardAllocationDriverData->ResourcePrivateDriverDataSize = 0;
2387 break;
2388 }
2389 case D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE:
2390 {
2391 LOGF(("D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE"));
2392 UINT bpp = vboxWddmCalcBitsPerPixel(pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format);
2393 Assert(bpp);
2394 if (bpp != 0)
2395 {
2396 UINT Pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Width, pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format);
2397 pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Pitch = Pitch;
2398
2399 /** @todo need [d/q]word align?? */
2400
2401 if (pGetStandardAllocationDriverData->pAllocationPrivateDriverData)
2402 {
2403 pAllocInfo = (PVBOXWDDM_ALLOCINFO)pGetStandardAllocationDriverData->pAllocationPrivateDriverData;
2404 pAllocInfo->enmType = VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE;
2405 pAllocInfo->SurfDesc.width = pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Width;
2406 pAllocInfo->SurfDesc.height = pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Height;
2407 pAllocInfo->SurfDesc.format = pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format;
2408 pAllocInfo->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pAllocInfo->SurfDesc.format);
2409 pAllocInfo->SurfDesc.pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Width, pAllocInfo->SurfDesc.format);
2410 pAllocInfo->SurfDesc.cbSize = vboxWddmCalcSize(pAllocInfo->SurfDesc.pitch, pAllocInfo->SurfDesc.height, pAllocInfo->SurfDesc.format);
2411 pAllocInfo->SurfDesc.depth = 0;
2412 pAllocInfo->SurfDesc.slicePitch = 0;
2413 pAllocInfo->SurfDesc.RefreshRate.Numerator = 0;
2414 pAllocInfo->SurfDesc.RefreshRate.Denominator = 1000;
2415 pAllocInfo->SurfDesc.VidPnSourceId = D3DDDI_ID_UNINITIALIZED;
2416
2417 pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Pitch = pAllocInfo->SurfDesc.pitch;
2418 }
2419 pGetStandardAllocationDriverData->AllocationPrivateDriverDataSize = sizeof (VBOXWDDM_ALLOCINFO);
2420
2421 pGetStandardAllocationDriverData->ResourcePrivateDriverDataSize = 0;
2422 }
2423 else
2424 {
2425 LOGREL(("Invalid format (%d)", pGetStandardAllocationDriverData->pCreateShadowSurfaceData->Format));
2426 Status = STATUS_INVALID_PARAMETER;
2427 }
2428 break;
2429 }
2430 case D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE:
2431 {
2432 LOGF(("D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE"));
2433 if(pGetStandardAllocationDriverData->pAllocationPrivateDriverData)
2434 {
2435 pAllocInfo = (PVBOXWDDM_ALLOCINFO)pGetStandardAllocationDriverData->pAllocationPrivateDriverData;
2436 pAllocInfo->enmType = VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE;
2437 pAllocInfo->SurfDesc.width = pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Width;
2438 pAllocInfo->SurfDesc.height = pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Height;
2439 pAllocInfo->SurfDesc.format = D3DDDIFMT_X8R8G8B8; /* staging has always always D3DDDIFMT_X8R8G8B8 */
2440 pAllocInfo->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pAllocInfo->SurfDesc.format);
2441 pAllocInfo->SurfDesc.pitch = vboxWddmCalcPitch(pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Width, pAllocInfo->SurfDesc.format);
2442 pAllocInfo->SurfDesc.cbSize = vboxWddmCalcSize(pAllocInfo->SurfDesc.pitch, pAllocInfo->SurfDesc.height, pAllocInfo->SurfDesc.format);
2443 pAllocInfo->SurfDesc.depth = 0;
2444 pAllocInfo->SurfDesc.slicePitch = 0;
2445 pAllocInfo->SurfDesc.RefreshRate.Numerator = 0;
2446 pAllocInfo->SurfDesc.RefreshRate.Denominator = 1000;
2447 pAllocInfo->SurfDesc.VidPnSourceId = D3DDDI_ID_UNINITIALIZED;
2448
2449 pGetStandardAllocationDriverData->pCreateStagingSurfaceData->Pitch = pAllocInfo->SurfDesc.pitch;
2450 }
2451 pGetStandardAllocationDriverData->AllocationPrivateDriverDataSize = sizeof (VBOXWDDM_ALLOCINFO);
2452
2453 pGetStandardAllocationDriverData->ResourcePrivateDriverDataSize = 0;
2454 break;
2455 }
2456//#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN7)
2457// case D3DKMDT_STANDARDALLOCATION_GDISURFACE:
2458//# error port to Win7 DDI
2459// break;
2460//#endif
2461 default:
2462 LOGREL(("Invalid allocation type (%d)", pGetStandardAllocationDriverData->StandardAllocationType));
2463 Status = STATUS_INVALID_PARAMETER;
2464 break;
2465 }
2466
2467 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
2468
2469 return Status;
2470}
2471
2472NTSTATUS
2473APIENTRY
2474DxgkDdiAcquireSwizzlingRange(
2475 CONST HANDLE hAdapter,
2476 DXGKARG_ACQUIRESWIZZLINGRANGE* pAcquireSwizzlingRange)
2477{
2478 RT_NOREF(hAdapter, pAcquireSwizzlingRange);
2479 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2480
2481 AssertBreakpoint();
2482
2483 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2484
2485 return STATUS_SUCCESS;
2486}
2487
2488NTSTATUS
2489APIENTRY
2490DxgkDdiReleaseSwizzlingRange(
2491 CONST HANDLE hAdapter,
2492 CONST DXGKARG_RELEASESWIZZLINGRANGE* pReleaseSwizzlingRange)
2493{
2494 RT_NOREF(hAdapter, pReleaseSwizzlingRange);
2495 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2496
2497 AssertBreakpoint();
2498
2499 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2500
2501 return STATUS_SUCCESS;
2502}
2503
2504typedef struct VBOXWDDM_CALL_ISR
2505{
2506 PVBOXMP_DEVEXT pDevExt;
2507 ULONG MessageNumber;
2508} VBOXWDDM_CALL_ISR, *PVBOXWDDM_CALL_ISR;
2509
2510static BOOLEAN vboxWddmCallIsrCb(PVOID Context)
2511{
2512 PVBOXWDDM_CALL_ISR pdc = (PVBOXWDDM_CALL_ISR)Context;
2513 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
2514 if (pDevExt->fCmdVbvaEnabled)
2515 {
2516 AssertFailed(); /* Should not be here, because this is not used with 3D gallium driver. */
2517 return FALSE;
2518 }
2519 return DxgkDdiInterruptRoutineLegacy(pDevExt, pdc->MessageNumber);
2520}
2521
2522NTSTATUS vboxWddmCallIsr(PVBOXMP_DEVEXT pDevExt)
2523{
2524 VBOXWDDM_CALL_ISR context;
2525 context.pDevExt = pDevExt;
2526 context.MessageNumber = 0;
2527 BOOLEAN bRet;
2528 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
2529 pDevExt->u.primary.DxgkInterface.DeviceHandle,
2530 vboxWddmCallIsrCb,
2531 &context,
2532 0, /* IN ULONG MessageNumber */
2533 &bRet);
2534 AssertNtStatusSuccess(Status);
2535 return Status;
2536}
2537
2538
2539NTSTATUS
2540APIENTRY
2541DxgkDdiSetPalette(
2542 CONST HANDLE hAdapter,
2543 CONST DXGKARG_SETPALETTE* pSetPalette
2544 )
2545{
2546 RT_NOREF(hAdapter, pSetPalette);
2547 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2548
2549 AssertBreakpoint();
2550 /** @todo fixme: implement */
2551
2552 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
2553
2554 return STATUS_SUCCESS;
2555}
2556
2557/** Find which area of a 32 bit mouse pointer bitmap is actually used.
2558 * Zero pixels on the right and the bottom of the bitmap are considered unused.
2559 *
2560 * @param pPixels The bitmap.
2561 * @param Pitch The bitmap scanline size in bytes.
2562 * @param Width The bitmap width.
2563 * @param Height The bitmap height.
2564 * @param piMaxFilledPixel Where to store the maximum index of non-zero pixel within a scanline.
2565 * @param piMaxFilledScanline Where to store the zero based index of the last scanline with non-zero pixels.
2566 */
2567static void vboxWddmPointerFindDimensionsColor(void const *pPixels, UINT Pitch, UINT Width, UINT Height,
2568 LONG *piMaxFilledPixel, LONG *piMaxFilledScanline)
2569{
2570 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2571 * Exclude zero pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2572 */
2573 DWORD const *pdwScanline = (DWORD *)pPixels;
2574 LONG iMaxFilledScanline = -1;
2575 LONG iMaxFilledPixel = -1;
2576 for (ULONG y = 0; y < Height; ++y)
2577 {
2578 LONG iLastFilledPixel = -1;
2579 for (ULONG x = 0; x < Width; ++x)
2580 {
2581 if (pdwScanline[x])
2582 iLastFilledPixel = x;
2583 }
2584
2585 iMaxFilledPixel = RT_MAX(iMaxFilledPixel, iLastFilledPixel);
2586
2587 if (iLastFilledPixel >= 0)
2588 {
2589 /* Scanline contains non-zero pixels. */
2590 iMaxFilledScanline = y;
2591 }
2592
2593 pdwScanline = (DWORD *)((uint8_t *)pdwScanline + Pitch);
2594 }
2595
2596 *piMaxFilledPixel = iMaxFilledPixel;
2597 *piMaxFilledScanline = iMaxFilledScanline;
2598}
2599
2600/** Find which area of a 1 bit AND/XOR mask bitmap is actually used, i.e. filled with actual data.
2601 * For the AND mask the bytes with a value 0xff on the right and the bottom of the bitmap are considered unused.
2602 * For the XOR mask the blank value is 0x00.
2603 *
2604 * @param pPixels The 1bit bitmap.
2605 * @param Pitch The 1bit bitmap scanline size in bytes.
2606 * @param Width The bitmap width.
2607 * @param Height The bitmap height.
2608 * @param Blank The value of the unused bytes in the supplied bitmap.
2609 * @param piMaxFilledPixel Where to store the maximum index of a filled pixel within a scanline.
2610 * @param piMaxFilledScanline Where to store the zero based index of the last scanline with filled pixels.
2611 */
2612static void vboxWddmPointerFindDimensionsMono(void const *pPixels, UINT Pitch, UINT Width, UINT Height, BYTE Blank,
2613 LONG *piMaxFilledPixel, LONG *piMaxFilledScanline)
2614{
2615 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2616 * Exclude the blank pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2617 */
2618 BYTE const *pbScanline = (BYTE *)pPixels;
2619 LONG iMaxFilledScanline = -1;
2620 LONG iMaxFilledByte = -1;
2621 for (ULONG y = 0; y < Height; ++y)
2622 {
2623 LONG iLastFilledByte = -1;
2624 for (ULONG x = 0; x < Width / 8; ++x)
2625 {
2626 if (pbScanline[x] != Blank)
2627 iLastFilledByte = x;
2628 }
2629
2630 iMaxFilledByte = RT_MAX(iMaxFilledByte, iLastFilledByte);
2631
2632 if (iLastFilledByte >= 0)
2633 {
2634 /* Scanline contains filled pixels. */
2635 iMaxFilledScanline = y;
2636 }
2637
2638 pbScanline += Pitch;
2639 }
2640
2641 *piMaxFilledPixel = iMaxFilledByte * 8;
2642 *piMaxFilledScanline = iMaxFilledScanline;
2643}
2644
2645/** Adjust the width and the height of the mouse pointer bitmap.
2646 * See comments in the function for the adjustment criteria.
2647 *
2648 * @param iMaxX The index of the rightmost pixel which we want to keep.
2649 * @param iMaxY The index of the bottom-most pixel which we want to keep.
2650 * @param XHot The mouse pointer hot spot.
2651 * @param YHot The mouse pointer hot spot.
2652 * @param pWidth Where to store the bitmap width.
2653 * @param pHeight Where to store the bitmap height.
2654 */
2655static void vboxWddmPointerAdjustDimensions(LONG iMaxX, LONG iMaxY, UINT XHot, UINT YHot,
2656 ULONG *pWidth, ULONG *pHeight)
2657{
2658 /* Both input parameters are zero based indexes, add 1 to get a width and a height. */
2659 ULONG W = iMaxX + 1;
2660 ULONG H = iMaxY + 1;
2661
2662 /* Always include the hotspot point. */
2663 W = RT_MAX(XHot, W);
2664 H = RT_MAX(YHot, H);
2665
2666 /* Align to 8 pixels, because the XOR/AND pointers are aligned like that.
2667 * The AND mask has one bit per pixel with 8 bits per byte.
2668 * In case the host can't deal with unaligned data.
2669 */
2670 W = RT_ALIGN_T(W, 8, ULONG);
2671 H = RT_ALIGN_T(H, 8, ULONG);
2672
2673 /* Do not send bitmaps with zero dimensions. Actually make the min size 32x32. */
2674 W = RT_MAX(32, W);
2675 H = RT_MAX(32, H);
2676
2677 /* Make it square. Some hosts are known to require square pointers. */
2678 W = RT_MAX(W, H);
2679 H = W;
2680
2681 /* Do not exceed the supported size.
2682 * Actually this should not be necessary because Windows never creates such pointers.
2683 */
2684 W = RT_MIN(W, VBOXWDDM_C_POINTER_MAX_WIDTH);
2685 H = RT_MIN(H, VBOXWDDM_C_POINTER_MAX_HEIGHT);
2686
2687 *pWidth = W;
2688 *pHeight = H;
2689}
2690
2691BOOL vboxWddmPointerCopyColorData(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVIDEO_POINTER_ATTRIBUTES pPointerAttributes,
2692 bool fDwordAlignScanlines)
2693{
2694 ULONG srcMaskW, srcMaskH;
2695 ULONG dstBytesPerLine;
2696 ULONG x, y;
2697 BYTE *pSrc, *pDst, bit;
2698
2699 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2700 * Exclude zero pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2701 */
2702 LONG iMaxFilledPixel;
2703 LONG iMaxFilledScanline;
2704 vboxWddmPointerFindDimensionsColor(pSetPointerShape->pPixels, pSetPointerShape->Pitch,
2705 pSetPointerShape->Width, pSetPointerShape->Height,
2706 &iMaxFilledPixel, &iMaxFilledScanline);
2707
2708 vboxWddmPointerAdjustDimensions(iMaxFilledPixel, iMaxFilledScanline,
2709 pSetPointerShape->XHot, pSetPointerShape->YHot,
2710 &srcMaskW, &srcMaskH);
2711
2712 pPointerAttributes->Width = srcMaskW;
2713 pPointerAttributes->Height = srcMaskH;
2714 pPointerAttributes->WidthInBytes = pPointerAttributes->Width * 4;
2715
2716 /* cnstruct and mask from alpha color channel */
2717 pSrc = (PBYTE)pSetPointerShape->pPixels;
2718 pDst = pPointerAttributes->Pixels;
2719 dstBytesPerLine = (pPointerAttributes->Width+7)/8;
2720 if (fDwordAlignScanlines)
2721 dstBytesPerLine = RT_ALIGN_T(dstBytesPerLine, 4, ULONG);
2722
2723 /* sanity check */
2724 uint32_t cbData = RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG)+
2725 pPointerAttributes->Height*pPointerAttributes->WidthInBytes;
2726 uint32_t cbPointerAttributes = RT_UOFFSETOF_DYN(VIDEO_POINTER_ATTRIBUTES, Pixels[cbData]);
2727 Assert(VBOXWDDM_POINTER_ATTRIBUTES_SIZE >= cbPointerAttributes);
2728 if (VBOXWDDM_POINTER_ATTRIBUTES_SIZE < cbPointerAttributes)
2729 {
2730 LOGREL(("VBOXWDDM_POINTER_ATTRIBUTES_SIZE(%d) < cbPointerAttributes(%d)", VBOXWDDM_POINTER_ATTRIBUTES_SIZE, cbPointerAttributes));
2731 return FALSE;
2732 }
2733
2734 memset(pDst, 0xFF, dstBytesPerLine*pPointerAttributes->Height);
2735 for (y=0; y<pPointerAttributes->Height; ++y)
2736 {
2737 for (x=0, bit=7; x<pPointerAttributes->Width; ++x, --bit)
2738 {
2739 if (0xFF==bit) bit=7;
2740
2741 if (pSrc[y*pSetPointerShape->Pitch + x*4 + 3] > 0x7F)
2742 {
2743 pDst[y*dstBytesPerLine + x/8] &= ~RT_BIT(bit);
2744 }
2745 }
2746 }
2747
2748 /* copy 32bpp to XOR DIB, it start in pPointerAttributes->Pixels should be 4bytes aligned */
2749 pSrc = (BYTE*)pSetPointerShape->pPixels;
2750 pDst = pPointerAttributes->Pixels + RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG);
2751 dstBytesPerLine = pPointerAttributes->Width * 4;
2752
2753 for (y=0; y<pPointerAttributes->Height; ++y)
2754 {
2755 memcpy(pDst+y*dstBytesPerLine, pSrc+y*pSetPointerShape->Pitch, dstBytesPerLine);
2756 }
2757
2758 return TRUE;
2759}
2760
2761BOOL vboxWddmPointerCopyMonoData(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVIDEO_POINTER_ATTRIBUTES pPointerAttributes,
2762 bool fDwordAlignScanlines)
2763{
2764 ULONG srcMaskW, srcMaskH;
2765 ULONG dstBytesPerLine;
2766 ULONG x, y;
2767 BYTE *pSrc, *pDst, bit;
2768
2769 /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
2770 * Exclude unused pixels (which are transparent anyway) from the right and the bottom of the bitmap.
2771 */
2772 LONG iMaxFilledPixelAND;
2773 LONG iMaxFilledScanlineAND;
2774 vboxWddmPointerFindDimensionsMono(pSetPointerShape->pPixels, pSetPointerShape->Pitch,
2775 pSetPointerShape->Width, pSetPointerShape->Height, 0xff,
2776 &iMaxFilledPixelAND, &iMaxFilledScanlineAND);
2777
2778 LONG iMaxFilledPixelXOR;
2779 LONG iMaxFilledScanlineXOR;
2780 vboxWddmPointerFindDimensionsMono((BYTE *)pSetPointerShape->pPixels + pSetPointerShape->Height * pSetPointerShape->Pitch,
2781 pSetPointerShape->Pitch,
2782 pSetPointerShape->Width, pSetPointerShape->Height, 0x00,
2783 &iMaxFilledPixelXOR, &iMaxFilledScanlineXOR);
2784
2785 LONG iMaxFilledPixel = RT_MAX(iMaxFilledPixelAND, iMaxFilledPixelXOR);
2786 LONG iMaxFilledScanline = RT_MAX(iMaxFilledScanlineAND, iMaxFilledScanlineXOR);
2787
2788 vboxWddmPointerAdjustDimensions(iMaxFilledPixel, iMaxFilledScanline,
2789 pSetPointerShape->XHot, pSetPointerShape->YHot,
2790 &srcMaskW, &srcMaskH);
2791
2792 pPointerAttributes->Width = srcMaskW;
2793 pPointerAttributes->Height = srcMaskH;
2794 pPointerAttributes->WidthInBytes = pPointerAttributes->Width * 4;
2795
2796 /* copy AND mask */
2797 pSrc = (PBYTE)pSetPointerShape->pPixels;
2798 pDst = pPointerAttributes->Pixels;
2799 dstBytesPerLine = (pPointerAttributes->Width+7)/8;
2800 if (fDwordAlignScanlines)
2801 dstBytesPerLine = RT_ALIGN_T(dstBytesPerLine, 4, ULONG);
2802
2803 for (y=0; y<pPointerAttributes->Height; ++y)
2804 {
2805 memcpy(pDst+y*dstBytesPerLine, pSrc+y*pSetPointerShape->Pitch, dstBytesPerLine);
2806 }
2807
2808 /* convert XOR mask to RGB0 DIB, it start in pPointerAttributes->Pixels should be 4bytes aligned */
2809 pSrc = (BYTE*)pSetPointerShape->pPixels + pSetPointerShape->Height*pSetPointerShape->Pitch;
2810 pDst = pPointerAttributes->Pixels + RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG);
2811 dstBytesPerLine = pPointerAttributes->Width * 4;
2812
2813 for (y=0; y<pPointerAttributes->Height; ++y)
2814 {
2815 for (x=0, bit=7; x<pPointerAttributes->Width; ++x, --bit)
2816 {
2817 if (0xFF==bit) bit=7;
2818
2819 *(ULONG*)&pDst[y*dstBytesPerLine+x*4] = (pSrc[y*pSetPointerShape->Pitch+x/8] & RT_BIT(bit)) ? 0x00FFFFFF : 0;
2820 }
2821 }
2822
2823 return TRUE;
2824}
2825
2826static BOOLEAN vboxVddmPointerShapeToAttributes(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVBOXWDDM_POINTER_INFO pPointerInfo,
2827 bool fDwordAlignScanlines)
2828{
2829 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = &pPointerInfo->Attributes.data;
2830 /* pPointerAttributes maintains the visibility state, clear all except visibility */
2831 pPointerAttributes->Enable &= VBOX_MOUSE_POINTER_VISIBLE;
2832
2833 Assert(pSetPointerShape->Flags.Value == 1 || pSetPointerShape->Flags.Value == 2);
2834 if (pSetPointerShape->Flags.Color)
2835 {
2836 if (vboxWddmPointerCopyColorData(pSetPointerShape, pPointerAttributes, fDwordAlignScanlines))
2837 {
2838 pPointerAttributes->Flags = VIDEO_MODE_COLOR_POINTER;
2839 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_ALPHA;
2840 }
2841 else
2842 {
2843 LOGREL(("vboxWddmPointerCopyColorData failed"));
2844 AssertBreakpoint();
2845 return FALSE;
2846 }
2847
2848 }
2849 else if (pSetPointerShape->Flags.Monochrome)
2850 {
2851 if (vboxWddmPointerCopyMonoData(pSetPointerShape, pPointerAttributes, fDwordAlignScanlines))
2852 {
2853 pPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER;
2854 }
2855 else
2856 {
2857 LOGREL(("vboxWddmPointerCopyMonoData failed"));
2858 AssertBreakpoint();
2859 return FALSE;
2860 }
2861 }
2862 else
2863 {
2864 LOGREL(("unsupported pointer type Flags.Value(0x%x)", pSetPointerShape->Flags.Value));
2865 AssertBreakpoint();
2866 return FALSE;
2867 }
2868
2869 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_SHAPE;
2870
2871 /*
2872 * The hot spot coordinates and alpha flag will be encoded in the pPointerAttributes::Enable field.
2873 * High word will contain hot spot info and low word - flags.
2874 */
2875 pPointerAttributes->Enable |= (pSetPointerShape->YHot & 0xFF) << 24;
2876 pPointerAttributes->Enable |= (pSetPointerShape->XHot & 0xFF) << 16;
2877
2878 return TRUE;
2879}
2880
2881bool vboxWddmUpdatePointerShape(PVBOXMP_DEVEXT pDevExt, PVIDEO_POINTER_ATTRIBUTES pAttrs, uint32_t cbLength)
2882{
2883#ifdef VBOX_WITH_MESA3D
2884 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VBOX)
2885 {
2886 NTSTATUS Status = STATUS_SUCCESS;
2887
2888 /** @todo Get rid of the unnecesary en-/decode procedure (XPDM legacy). */
2889 uint32_t fFlags = pAttrs->Enable & 0x0000FFFF;
2890 uint32_t xHot = (pAttrs->Enable >> 16) & 0xFF;
2891 uint32_t yHot = (pAttrs->Enable >> 24) & 0xFF;
2892 uint32_t cWidth = pAttrs->Width;
2893 uint32_t cHeight = pAttrs->Height;
2894 uint32_t cbAndMask = 0;
2895 uint32_t cbXorMask = 0;
2896
2897 if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
2898 {
2899 /* Size of the pointer data: sizeof(AND mask) + sizeof(XOR mask) */
2900 /* "Each scanline is padded to a 32-bit boundary." */
2901 cbAndMask = ((((cWidth + 7) / 8) + 3) & ~3) * cHeight;
2902 cbXorMask = cWidth * 4 * cHeight;
2903
2904 /* Send the shape to the host. */
2905 if (fFlags & VBOX_MOUSE_POINTER_ALPHA)
2906 {
2907 void const *pvImage = &pAttrs->Pixels[cbAndMask];
2908 Status = GaDefineAlphaCursor(pDevExt->pGa,
2909 xHot,
2910 yHot,
2911 cWidth,
2912 cHeight,
2913 pvImage,
2914 cbXorMask);
2915 }
2916 else
2917 {
2918 uint32_t u32AndMaskDepth = 1;
2919 uint32_t u32XorMaskDepth = 32;
2920
2921 void const *pvAndMask = &pAttrs->Pixels[0];
2922 void const *pvXorMask = &pAttrs->Pixels[cbAndMask];
2923 Status = GaDefineCursor(pDevExt->pGa,
2924 xHot,
2925 yHot,
2926 cWidth,
2927 cHeight,
2928 u32AndMaskDepth,
2929 u32XorMaskDepth,
2930 pvAndMask,
2931 cbAndMask,
2932 pvXorMask,
2933 cbXorMask);
2934 }
2935 }
2936
2937 /** @todo Hack: Use the legacy interface to handle visibility.
2938 * Eventually the VMSVGA WDDM driver should use the SVGA_FIFO_CURSOR_* interface.
2939 */
2940 VIDEO_POINTER_ATTRIBUTES attrs;
2941 RT_ZERO(attrs);
2942 attrs.Enable = pAttrs->Enable & VBOX_MOUSE_POINTER_VISIBLE;
2943 if (!VBoxMPCmnUpdatePointerShape(VBoxCommonFromDeviceExt(pDevExt), &attrs, sizeof(attrs)))
2944 {
2945 Status = STATUS_INVALID_PARAMETER;
2946 }
2947
2948 return Status == STATUS_SUCCESS;
2949 }
2950#endif
2951
2952 /* VBOXVIDEO_HWTYPE_VBOX */
2953 return VBoxMPCmnUpdatePointerShape(VBoxCommonFromDeviceExt(pDevExt), pAttrs, cbLength);
2954}
2955
2956static void vboxWddmHostPointerEnable(PVBOXMP_DEVEXT pDevExt, BOOLEAN fEnable)
2957{
2958 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
2959 RT_ZERO(PointerAttributes);
2960 if (fEnable)
2961 {
2962 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
2963 }
2964 vboxWddmUpdatePointerShape(pDevExt, &PointerAttributes, sizeof(PointerAttributes));
2965}
2966
2967NTSTATUS
2968APIENTRY
2969DxgkDdiSetPointerPosition(
2970 CONST HANDLE hAdapter,
2971 CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
2972{
2973// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
2974
2975 vboxVDbgBreakFv();
2976
2977 /* mouse integration is ON */
2978 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
2979 PVBOXWDDM_POINTER_INFO pPointerInfo = &pDevExt->aSources[pSetPointerPosition->VidPnSourceId].PointerInfo;
2980 PVBOXWDDM_GLOBAL_POINTER_INFO pGlobalPointerInfo = &pDevExt->PointerInfo;
2981 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = &pPointerInfo->Attributes.data;
2982 BOOLEAN fScreenVisState = !!(pPointerAttributes->Enable & VBOX_MOUSE_POINTER_VISIBLE);
2983 BOOLEAN fVisStateChanged = FALSE;
2984 BOOLEAN fScreenChanged = pGlobalPointerInfo->iLastReportedScreen != pSetPointerPosition->VidPnSourceId;
2985
2986 if (pSetPointerPosition->Flags.Visible)
2987 {
2988 pPointerAttributes->Enable |= VBOX_MOUSE_POINTER_VISIBLE;
2989 if (!fScreenVisState)
2990 {
2991 fVisStateChanged = TRUE;
2992 }
2993 }
2994 else
2995 {
2996 pPointerAttributes->Enable &= ~VBOX_MOUSE_POINTER_VISIBLE;
2997 if (fScreenVisState)
2998 {
2999 fVisStateChanged = TRUE;
3000 }
3001 }
3002
3003 pGlobalPointerInfo->iLastReportedScreen = pSetPointerPosition->VidPnSourceId;
3004
3005 if ((fVisStateChanged || fScreenChanged) && VBoxQueryHostWantsAbsolute())
3006 {
3007 if (fScreenChanged)
3008 {
3009 BOOLEAN bResult = vboxWddmUpdatePointerShape(pDevExt, &pPointerInfo->Attributes.data, VBOXWDDM_POINTER_ATTRIBUTES_SIZE);
3010 if (!bResult)
3011 {
3012 vboxWddmHostPointerEnable(pDevExt, FALSE);
3013 }
3014 }
3015
3016 // Always update the visibility as requested. Tell the host to use the guest's pointer.
3017 vboxWddmHostPointerEnable(pDevExt, pSetPointerPosition->Flags.Visible);
3018 }
3019
3020// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3021
3022 return STATUS_SUCCESS;
3023}
3024
3025NTSTATUS
3026APIENTRY
3027DxgkDdiSetPointerShape(
3028 CONST HANDLE hAdapter,
3029 CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
3030{
3031// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3032
3033 vboxVDbgBreakFv();
3034
3035 NTSTATUS Status = STATUS_NOT_SUPPORTED;
3036
3037 if (VBoxQueryHostWantsAbsolute())
3038 {
3039 /* mouse integration is ON */
3040 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3041 PVBOXWDDM_POINTER_INFO pPointerInfo = &pDevExt->aSources[pSetPointerShape->VidPnSourceId].PointerInfo;
3042 bool const fDwordAlignScanlines = pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VBOX;
3043 /** @todo to avoid extra data copy and extra heap allocation,
3044 * need to maintain the pre-allocated HGSMI buffer and convert the data directly to it */
3045 if (vboxVddmPointerShapeToAttributes(pSetPointerShape, pPointerInfo, fDwordAlignScanlines))
3046 {
3047 pDevExt->PointerInfo.iLastReportedScreen = pSetPointerShape->VidPnSourceId;
3048 if (vboxWddmUpdatePointerShape(pDevExt, &pPointerInfo->Attributes.data, VBOXWDDM_POINTER_ATTRIBUTES_SIZE))
3049 Status = STATUS_SUCCESS;
3050 else
3051 {
3052 // tell the host to use the guest's pointer
3053 vboxWddmHostPointerEnable(pDevExt, FALSE);
3054 }
3055 }
3056 }
3057
3058// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3059
3060 return Status;
3061}
3062
3063NTSTATUS
3064APIENTRY CALLBACK
3065DxgkDdiResetFromTimeout(
3066 CONST HANDLE hAdapter)
3067{
3068 RT_NOREF(hAdapter);
3069 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3070
3071 AssertBreakpoint();
3072 /** @todo fixme: implement */
3073
3074 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3075
3076 return STATUS_SUCCESS;
3077}
3078
3079
3080/* the lpRgnData->Buffer comes to us as RECT
3081 * to avoid extra memcpy we cast it to PRTRECT assuming
3082 * they are identical */
3083AssertCompile(sizeof(RECT) == sizeof(RTRECT));
3084AssertCompile(RT_OFFSETOF(RECT, left) == RT_OFFSETOF(RTRECT, xLeft));
3085AssertCompile(RT_OFFSETOF(RECT, bottom) == RT_OFFSETOF(RTRECT, yBottom));
3086AssertCompile(RT_OFFSETOF(RECT, right) == RT_OFFSETOF(RTRECT, xRight));
3087AssertCompile(RT_OFFSETOF(RECT, top) == RT_OFFSETOF(RTRECT, yTop));
3088
3089NTSTATUS
3090APIENTRY
3091DxgkDdiEscape(
3092 CONST HANDLE hAdapter,
3093 CONST DXGKARG_ESCAPE* pEscape)
3094{
3095 PAGED_CODE();
3096
3097// LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3098
3099 NTSTATUS Status = STATUS_NOT_SUPPORTED;
3100 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3101 Assert(pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE));
3102 if (pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE))
3103 {
3104 PVBOXDISPIFESCAPE pEscapeHdr = (PVBOXDISPIFESCAPE)pEscape->pPrivateDriverData;
3105 switch (pEscapeHdr->escapeCode)
3106 {
3107 case VBOXESC_SETVISIBLEREGION:
3108 {
3109#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3110 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3111 if (!pContext)
3112 {
3113 WARN(("VBOXESC_SETVISIBLEREGION no context supplied!"));
3114 Status = STATUS_INVALID_PARAMETER;
3115 break;
3116 }
3117
3118 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS)
3119 {
3120 WARN(("VBOXESC_SETVISIBLEREGION invalid context supplied %d!", pContext->enmType));
3121 Status = STATUS_INVALID_PARAMETER;
3122 break;
3123 }
3124#endif
3125 /* visible regions for seamless */
3126 LPRGNDATA lpRgnData = VBOXDISPIFESCAPE_DATA(pEscapeHdr, RGNDATA);
3127 uint32_t cbData = VBOXDISPIFESCAPE_DATA_SIZE(pEscape->PrivateDriverDataSize);
3128 uint32_t cbRects = cbData - RT_UOFFSETOF(RGNDATA, Buffer);
3129 /* the lpRgnData->Buffer comes to us as RECT
3130 * to avoid extra memcpy we cast it to PRTRECT assuming
3131 * they are identical
3132 * see AssertCompile's above */
3133
3134 RTRECT *pRect = (RTRECT *)&lpRgnData->Buffer;
3135
3136 uint32_t cRects = cbRects/sizeof(RTRECT);
3137 int rc;
3138
3139 LOG(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRects=%d", cRects));
3140 Assert(cbRects >= sizeof(RTRECT)
3141 && cbRects == cRects*sizeof(RTRECT)
3142 && cRects == lpRgnData->rdh.nCount);
3143 if ( cbRects >= sizeof(RTRECT)
3144 && cbRects == cRects*sizeof(RTRECT)
3145 && cRects == lpRgnData->rdh.nCount)
3146 {
3147 /*
3148 * Inform the host about the visible region
3149 */
3150 VMMDevVideoSetVisibleRegion *req = NULL;
3151
3152 rc = VbglR0GRAlloc ((VMMDevRequestHeader **)&req,
3153 sizeof (VMMDevVideoSetVisibleRegion) + (cRects-1)*sizeof(RTRECT),
3154 VMMDevReq_VideoSetVisibleRegion);
3155 AssertRC(rc);
3156 if (RT_SUCCESS(rc))
3157 {
3158 req->cRect = cRects;
3159 memcpy(&req->Rect, pRect, cRects*sizeof(RTRECT));
3160
3161 rc = VbglR0GRPerform (&req->header);
3162 AssertRC(rc);
3163 if (RT_SUCCESS(rc))
3164 Status = STATUS_SUCCESS;
3165 else
3166 {
3167 WARN(("VbglR0GRPerform failed rc (%d)", rc));
3168 Status = STATUS_UNSUCCESSFUL;
3169 }
3170 }
3171 else
3172 {
3173 WARN(("VbglR0GRAlloc failed rc (%d)", rc));
3174 Status = STATUS_UNSUCCESSFUL;
3175 }
3176 }
3177 else
3178 {
3179 WARN(("VBOXESC_SETVISIBLEREGION: incorrect buffer size (%d), reported count (%d)", cbRects, lpRgnData->rdh.nCount));
3180 Status = STATUS_INVALID_PARAMETER;
3181 }
3182 break;
3183 }
3184 case VBOXESC_ISVRDPACTIVE:
3185 /** @todo implement */
3186 Status = STATUS_SUCCESS;
3187 break;
3188 case VBOXESC_CONFIGURETARGETS:
3189 {
3190 LOG(("=> VBOXESC_CONFIGURETARGETS"));
3191
3192 if (!pEscape->Flags.HardwareAccess)
3193 {
3194 WARN(("VBOXESC_CONFIGURETARGETS called without HardwareAccess flag set, failing"));
3195 Status = STATUS_INVALID_PARAMETER;
3196 break;
3197 }
3198
3199#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3200 /* win8.1 does not allow context-based escapes for display-only mode */
3201 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3202 if (!pContext)
3203 {
3204 WARN(("VBOXESC_CONFIGURETARGETS no context supplied!"));
3205 Status = STATUS_INVALID_PARAMETER;
3206 break;
3207 }
3208
3209 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE)
3210 {
3211 WARN(("VBOXESC_CONFIGURETARGETS invalid context supplied %d!", pContext->enmType));
3212 Status = STATUS_INVALID_PARAMETER;
3213 break;
3214 }
3215#endif
3216
3217 if (pEscape->PrivateDriverDataSize != sizeof (*pEscapeHdr))
3218 {
3219 WARN(("VBOXESC_CONFIGURETARGETS invalid private driver size %d", pEscape->PrivateDriverDataSize));
3220 Status = STATUS_INVALID_PARAMETER;
3221 break;
3222 }
3223
3224 if (pEscapeHdr->u32CmdSpecific)
3225 {
3226 WARN(("VBOXESC_CONFIGURETARGETS invalid command %d", pEscapeHdr->u32CmdSpecific));
3227 Status = STATUS_INVALID_PARAMETER;
3228 break;
3229 }
3230
3231 HANDLE hKey = NULL;
3232 uint32_t cAdjusted = 0;
3233
3234 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3235 {
3236 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
3237 if (pTarget->fConfigured)
3238 continue;
3239
3240 pTarget->fConfigured = true;
3241
3242 if (!pTarget->fConnected)
3243 {
3244 Status = VBoxWddmChildStatusConnect(pDevExt, (uint32_t)i, TRUE);
3245 if (NT_SUCCESS(Status))
3246 ++cAdjusted;
3247 else
3248 WARN(("VBOXESC_CONFIGURETARGETS vboxWddmChildStatusConnectSecondaries failed Status 0x%x\n", Status));
3249 }
3250
3251 if (!hKey)
3252 {
3253 Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE, &hKey);
3254 if (!NT_SUCCESS(Status))
3255 {
3256 WARN(("VBOXESC_CONFIGURETARGETS IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
3257 hKey = NULL;
3258 continue;
3259 }
3260 }
3261
3262 Assert(hKey);
3263
3264 WCHAR wszNameBuf[sizeof(VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX) / sizeof(WCHAR) + 32];
3265 RTUtf16Printf(wszNameBuf, RT_ELEMENTS(wszNameBuf), "%ls%d", VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX, i);
3266 Status = vboxWddmRegSetValueDword(hKey, wszNameBuf, VBOXWDDM_CFG_DRVTARGET_CONNECTED);
3267 if (!NT_SUCCESS(Status))
3268 WARN(("VBOXESC_CONFIGURETARGETS vboxWddmRegSetValueDword (%ls) failed Status 0x%x\n", wszNameBuf, Status));
3269
3270 }
3271
3272 if (hKey)
3273 {
3274 NTSTATUS rcNt2 = ZwClose(hKey);
3275 Assert(rcNt2 == STATUS_SUCCESS); NOREF(rcNt2);
3276 }
3277
3278 pEscapeHdr->u32CmdSpecific = cAdjusted;
3279
3280 Status = STATUS_SUCCESS;
3281
3282 LOG(("<= VBOXESC_CONFIGURETARGETS"));
3283 break;
3284 }
3285 case VBOXESC_SETALLOCHOSTID:
3286 {
3287 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)pEscape->hDevice;
3288 if (!pDevice)
3289 {
3290 WARN(("VBOXESC_SETALLOCHOSTID called without no device specified, failing"));
3291 Status = STATUS_INVALID_PARAMETER;
3292 break;
3293 }
3294
3295 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_SETALLOCHOSTID))
3296 {
3297 WARN(("invalid buffer size for VBOXDISPIFESCAPE_SETALLOCHOSTID, was(%d), but expected (%d)",
3298 pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE_SETALLOCHOSTID)));
3299 Status = STATUS_INVALID_PARAMETER;
3300 break;
3301 }
3302
3303 if (!pEscape->Flags.HardwareAccess)
3304 {
3305 WARN(("VBOXESC_SETALLOCHOSTID not HardwareAccess"));
3306 Status = STATUS_INVALID_PARAMETER;
3307 break;
3308 }
3309
3310 PVBOXDISPIFESCAPE_SETALLOCHOSTID pSetHostID = (PVBOXDISPIFESCAPE_SETALLOCHOSTID)pEscapeHdr;
3311 PVBOXWDDM_ALLOCATION pAlloc = vboxWddmGetAllocationFromHandle(pDevExt, (D3DKMT_HANDLE)pSetHostID->hAlloc);
3312 if (!pAlloc)
3313 {
3314 WARN(("failed to get allocation from handle"));
3315 Status = STATUS_INVALID_PARAMETER;
3316 break;
3317 }
3318
3319 if (pAlloc->enmType != VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE)
3320 {
3321 WARN(("setHostID: invalid allocation type: %d", pAlloc->enmType));
3322 Status = STATUS_INVALID_PARAMETER;
3323 break;
3324 }
3325
3326 pSetHostID->rc = VBoxWddmOaSetHostID(pDevice, pAlloc, pSetHostID->hostID, &pSetHostID->EscapeHdr.u32CmdSpecific);
3327
3328 if (pAlloc->bAssigned)
3329 {
3330 PVBOXMP_DEVEXT pDevExt2 = pDevice->pAdapter;
3331 Assert(pAlloc->AllocData.SurfDesc.VidPnSourceId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt2)->cDisplays);
3332 PVBOXWDDM_SOURCE pSource = &pDevExt2->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
3333 if (pSource->AllocData.hostID != pAlloc->AllocData.hostID)
3334 {
3335 pSource->AllocData.hostID = pAlloc->AllocData.hostID;
3336 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
3337
3338 vboxWddmGhDisplayCheckSetInfo(pDevExt2);
3339 }
3340 }
3341
3342 Status = STATUS_SUCCESS;
3343 break;
3344 }
3345 case VBOXESC_ISANYX:
3346 {
3347 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_ISANYX))
3348 {
3349 WARN(("invalid private driver size %d", pEscape->PrivateDriverDataSize));
3350 Status = STATUS_INVALID_PARAMETER;
3351 break;
3352 }
3353
3354 PVBOXDISPIFESCAPE_ISANYX pIsAnyX = (PVBOXDISPIFESCAPE_ISANYX)pEscapeHdr;
3355 pIsAnyX->u32IsAnyX = VBoxCommonFromDeviceExt(pDevExt)->fAnyX;
3356 Status = STATUS_SUCCESS;
3357 break;
3358 }
3359 case VBOXESC_UPDATEMODES:
3360 {
3361 LOG(("=> VBOXESC_UPDATEMODES"));
3362
3363 if (!pEscape->Flags.HardwareAccess)
3364 {
3365 WARN(("VBOXESC_UPDATEMODES called without HardwareAccess flag set, failing"));
3366 Status = STATUS_INVALID_PARAMETER;
3367 break;
3368 }
3369
3370#ifdef VBOX_DISPIF_WITH_OPCONTEXT
3371 /* win8.1 does not allow context-based escapes for display-only mode */
3372 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext;
3373 if (!pContext)
3374 {
3375 WARN(("VBOXESC_UPDATEMODES no context supplied!"));
3376 Status = STATUS_INVALID_PARAMETER;
3377 break;
3378 }
3379
3380 if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE)
3381 {
3382 WARN(("VBOXESC_UPDATEMODES invalid context supplied %d!", pContext->enmType));
3383 Status = STATUS_INVALID_PARAMETER;
3384 break;
3385 }
3386#endif
3387
3388 if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_UPDATEMODES))
3389 {
3390 WARN(("VBOXESC_UPDATEMODES invalid private driver size %d", pEscape->PrivateDriverDataSize));
3391 Status = STATUS_INVALID_PARAMETER;
3392 break;
3393 }
3394
3395 VBOXDISPIFESCAPE_UPDATEMODES *pData = (VBOXDISPIFESCAPE_UPDATEMODES*)pEscapeHdr;
3396 Status = VBoxVidPnUpdateModes(pDevExt, pData->u32TargetId, &pData->Size);
3397 if (!NT_SUCCESS(Status))
3398 {
3399 WARN(("VBoxVidPnUpdateModes failed Status(%#x)\n", Status));
3400 return Status;
3401 }
3402
3403 Status = STATUS_SUCCESS;
3404 break;
3405 }
3406 case VBOXESC_TARGET_CONNECTIVITY:
3407 {
3408 if (!pEscape->Flags.HardwareAccess)
3409 {
3410 WARN(("VBOXESC_TARGET_CONNECTIVITY called without HardwareAccess flag set, failing"));
3411 Status = STATUS_INVALID_PARAMETER;
3412 break;
3413 }
3414
3415 if (pEscape->PrivateDriverDataSize != sizeof(VBOXDISPIFESCAPE_TARGETCONNECTIVITY))
3416 {
3417 WARN(("VBOXESC_TARGET_CONNECTIVITY invalid private driver size %d", pEscape->PrivateDriverDataSize));
3418 Status = STATUS_INVALID_PARAMETER;
3419 break;
3420 }
3421
3422 VBOXDISPIFESCAPE_TARGETCONNECTIVITY *pData = (VBOXDISPIFESCAPE_TARGETCONNECTIVITY *)pEscapeHdr;
3423 LOG(("=> VBOXESC_TARGET_CONNECTIVITY[%d] 0x%08X", pData->u32TargetId, pData->fu32Connect));
3424
3425 if (pData->u32TargetId >= (uint32_t)VBoxCommonFromDeviceExt(pDevExt)->cDisplays)
3426 {
3427 WARN(("VBOXESC_TARGET_CONNECTIVITY invalid screen index 0x%x", pData->u32TargetId));
3428 Status = STATUS_INVALID_PARAMETER;
3429 break;
3430 }
3431
3432 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[pData->u32TargetId];
3433 pTarget->fDisabled = !RT_BOOL(pData->fu32Connect & 1);
3434 pTarget->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_TOPOLOGY;
3435
3436 Status = STATUS_SUCCESS;
3437 break;
3438 }
3439 case VBOXESC_DBGPRINT:
3440 {
3441 /* use RT_OFFSETOF instead of sizeof since sizeof will give an aligned size that might
3442 * be bigger than the VBOXDISPIFESCAPE_DBGPRINT with a data containing just a few chars */
3443 Assert(pEscape->PrivateDriverDataSize >= RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]));
3444 /* only do DbgPrint when pEscape->PrivateDriverDataSize > RT_OFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1])
3445 * since == RT_OFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]) means the buffer contains just \0,
3446 * i.e. no need to print it */
3447 if (pEscape->PrivateDriverDataSize > RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGPRINT, aStringBuf[1]))
3448 {
3449 PVBOXDISPIFESCAPE_DBGPRINT pDbgPrint = (PVBOXDISPIFESCAPE_DBGPRINT)pEscapeHdr;
3450 /* ensure the last char is \0*/
3451 if (*((uint8_t*)pDbgPrint + pEscape->PrivateDriverDataSize - 1) == '\0')
3452 {
3453 if (g_VBoxLogUm & VBOXWDDM_CFG_LOG_UM_DBGPRINT)
3454 DbgPrint("%s\n", pDbgPrint->aStringBuf);
3455 if (g_VBoxLogUm & VBOXWDDM_CFG_LOG_UM_BACKDOOR)
3456 LOGREL_EXACT(("%s\n", pDbgPrint->aStringBuf));
3457 }
3458 }
3459 Status = STATUS_SUCCESS;
3460 break;
3461 }
3462 case VBOXESC_DBGDUMPBUF:
3463 {
3464 Status = vboxUmdDumpBuf((PVBOXDISPIFESCAPE_DBGDUMPBUF)pEscapeHdr, pEscape->PrivateDriverDataSize);
3465 break;
3466 }
3467 case VBOXESC_GUEST_DISPLAYCHANGED:
3468 {
3469 LOG(("=> VBOXESC_GUEST_DISPLAYCHANGED"));
3470
3471 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3472 {
3473#ifdef VBOX_WITH_MESA3D
3474 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3475 {
3476 GaVidPnSourceCheckPos(pDevExt, i);
3477 continue;
3478 }
3479#endif
3480
3481 vboxWddmDisplaySettingsCheckPos(pDevExt, i);
3482 }
3483 Status = STATUS_SUCCESS;
3484 break;
3485 }
3486 default:
3487#ifdef VBOX_WITH_MESA3D
3488 Status = GaDxgkDdiEscape(hAdapter, pEscape);
3489 if (NT_SUCCESS(Status) || Status != STATUS_NOT_SUPPORTED)
3490 break;
3491#endif
3492 WARN(("unsupported escape code (0x%x)", pEscapeHdr->escapeCode));
3493 break;
3494 }
3495 }
3496 else
3497 {
3498 WARN(("pEscape->PrivateDriverDataSize(%d) < (%d)", pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE)));
3499 Status = STATUS_BUFFER_TOO_SMALL;
3500 }
3501
3502// LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3503
3504 return Status;
3505}
3506
3507NTSTATUS
3508APIENTRY
3509DxgkDdiCollectDbgInfo(
3510 CONST HANDLE hAdapter,
3511 CONST DXGKARG_COLLECTDBGINFO* pCollectDbgInfo
3512 )
3513{
3514 RT_NOREF(hAdapter, pCollectDbgInfo);
3515 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3516
3517 AssertBreakpoint();
3518
3519 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3520
3521 return STATUS_SUCCESS;
3522}
3523
3524NTSTATUS
3525APIENTRY
3526DxgkDdiIsSupportedVidPn(
3527 CONST HANDLE hAdapter,
3528 OUT DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPnArg
3529 )
3530{
3531 /* The DxgkDdiIsSupportedVidPn should be made pageable. */
3532 PAGED_CODE();
3533
3534 LOGF(("ENTER, context(0x%x)", hAdapter));
3535
3536 vboxVDbgBreakFv();
3537
3538 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3539 NTSTATUS Status = VBoxVidPnIsSupported(pDevExt, pIsSupportedVidPnArg->hDesiredVidPn, &pIsSupportedVidPnArg->IsVidPnSupported);
3540 if (!NT_SUCCESS(Status))
3541 {
3542 WARN(("VBoxVidPnIsSupported failed Status(%#x)\n", Status));
3543 return Status;
3544 }
3545
3546 LOGF(("LEAVE, isSupported(%d), context(0x%x)", pIsSupportedVidPnArg->IsVidPnSupported, hAdapter));
3547
3548 return STATUS_SUCCESS;
3549}
3550
3551NTSTATUS
3552APIENTRY
3553DxgkDdiRecommendFunctionalVidPn(
3554 CONST HANDLE hAdapter,
3555 CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPnArg
3556 )
3557{
3558 /* The DxgkDdiRecommendFunctionalVidPn should be made pageable. */
3559 PAGED_CODE();
3560
3561 LOGF(("ENTER, context(0x%x)", hAdapter));
3562
3563 vboxVDbgBreakFv();
3564
3565 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3566
3567 if (pRecommendFunctionalVidPnArg->PrivateDriverDataSize != sizeof (VBOXWDDM_RECOMMENDVIDPN))
3568 {
3569 WARN(("invalid size"));
3570 return STATUS_INVALID_PARAMETER;
3571 }
3572
3573 VBOXWDDM_RECOMMENDVIDPN *pData = (VBOXWDDM_RECOMMENDVIDPN*)pRecommendFunctionalVidPnArg->pPrivateDriverData;
3574 Assert(pData);
3575
3576 NTSTATUS Status = VBoxVidPnRecommendFunctional(pDevExt, pRecommendFunctionalVidPnArg->hRecommendedFunctionalVidPn, pData);
3577 if (!NT_SUCCESS(Status))
3578 {
3579 WARN(("VBoxVidPnRecommendFunctional failed %#x", Status));
3580 return Status;
3581 }
3582
3583 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3584
3585 return STATUS_SUCCESS;
3586}
3587
3588NTSTATUS
3589APIENTRY
3590DxgkDdiEnumVidPnCofuncModality(
3591 CONST HANDLE hAdapter,
3592 CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModalityArg
3593 )
3594{
3595 /* The DxgkDdiEnumVidPnCofuncModality function should be made pageable. */
3596 PAGED_CODE();
3597
3598 LOGF(("ENTER, context(0x%x)", hAdapter));
3599
3600 vboxVDbgBreakFv();
3601
3602 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3603
3604 NTSTATUS Status = VBoxVidPnCofuncModality(pDevExt, pEnumCofuncModalityArg->hConstrainingVidPn, pEnumCofuncModalityArg->EnumPivotType, &pEnumCofuncModalityArg->EnumPivot);
3605 if (!NT_SUCCESS(Status))
3606 {
3607 WARN(("VBoxVidPnCofuncModality failed Status(%#x)\n", Status));
3608 return Status;
3609 }
3610
3611 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3612
3613 return STATUS_SUCCESS;
3614}
3615
3616NTSTATUS
3617APIENTRY
3618DxgkDdiSetVidPnSourceAddress(
3619 CONST HANDLE hAdapter,
3620 CONST DXGKARG_SETVIDPNSOURCEADDRESS* pSetVidPnSourceAddress
3621 )
3622{
3623 /* The DxgkDdiSetVidPnSourceAddress function should be made pageable. */
3624 PAGED_CODE();
3625
3626 vboxVDbgBreakFv();
3627
3628 LOGF(("ENTER, context(0x%x)", hAdapter));
3629 LOG(("id %d, seg %d, addr 0x%RX64, hAllocation %p, ctx cnt %d, f 0x%x",
3630 pSetVidPnSourceAddress->VidPnSourceId,
3631 pSetVidPnSourceAddress->PrimarySegment,
3632 pSetVidPnSourceAddress->PrimaryAddress.QuadPart,
3633 pSetVidPnSourceAddress->hAllocation,
3634 pSetVidPnSourceAddress->ContextCount,
3635 pSetVidPnSourceAddress->Flags.Value));
3636
3637 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3638 if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceAddress->VidPnSourceId)
3639 {
3640 WARN(("invalid VidPnSourceId (%d), for displays(%d)", pSetVidPnSourceAddress->VidPnSourceId, VBoxCommonFromDeviceExt(pDevExt)->cDisplays));
3641 return STATUS_INVALID_PARAMETER;
3642 }
3643
3644#ifdef VBOX_WITH_MESA3D
3645 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VMSVGA)
3646#endif
3647 vboxWddmDisplaySettingsCheckPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId);
3648
3649 NTSTATUS Status = STATUS_SUCCESS;
3650 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceAddress->VidPnSourceId];
3651
3652 /*
3653 * Update the source VRAM address.
3654 */
3655 PVBOXWDDM_ALLOCATION pAllocation;
3656 Assert(pSetVidPnSourceAddress->hAllocation);
3657 Assert(pSetVidPnSourceAddress->hAllocation || pSource->pPrimaryAllocation);
3658 Assert (pSetVidPnSourceAddress->Flags.Value < 2); /* i.e. 0 or 1 (ModeChange) */
3659
3660 if (pSetVidPnSourceAddress->hAllocation)
3661 {
3662 pAllocation = (PVBOXWDDM_ALLOCATION)pSetVidPnSourceAddress->hAllocation;
3663 vboxWddmAssignPrimary(pSource, pAllocation, pSetVidPnSourceAddress->VidPnSourceId);
3664 }
3665 else
3666 pAllocation = pSource->pPrimaryAllocation;
3667
3668 if (pAllocation)
3669 {
3670 vboxWddmAddrSetVram(&pAllocation->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment, (VBOXVIDEOOFFSET)pSetVidPnSourceAddress->PrimaryAddress.QuadPart);
3671 }
3672
3673 if (g_VBoxDisplayOnly && !pAllocation)
3674 {
3675 /* the VRAM here is an absolute address, nto an offset!
3676 * convert to offset since all internal VBox functionality is offset-based */
3677 vboxWddmAddrSetVram(&pSource->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment,
3678 vboxWddmVramAddrToOffset(pDevExt, pSetVidPnSourceAddress->PrimaryAddress));
3679 }
3680 else
3681 {
3682 Assert(!g_VBoxDisplayOnly);
3683 vboxWddmAddrSetVram(&pSource->AllocData.Addr, pSetVidPnSourceAddress->PrimarySegment,
3684 pSetVidPnSourceAddress->PrimaryAddress.QuadPart);
3685 }
3686
3687 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
3688
3689 /*
3690 * Report the source.
3691 */
3692#ifdef VBOX_WITH_MESA3D
3693 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3694 {
3695 /* Query the position of the screen to make sure it is up to date. */
3696 vboxWddmDisplaySettingsQueryPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId, &pSource->VScreenPos);
3697
3698 GaVidPnSourceReport(pDevExt, pSource);
3699 return STATUS_SUCCESS;
3700 }
3701#endif
3702
3703 vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
3704
3705 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3706
3707 return Status;
3708}
3709
3710NTSTATUS
3711APIENTRY
3712DxgkDdiSetVidPnSourceVisibility(
3713 CONST HANDLE hAdapter,
3714 CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility
3715 )
3716{
3717 /* DxgkDdiSetVidPnSourceVisibility should be made pageable. */
3718 PAGED_CODE();
3719
3720 vboxVDbgBreakFv();
3721
3722 LOGF(("ENTER, context(0x%x)", hAdapter));
3723
3724 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3725
3726 if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceVisibility->VidPnSourceId)
3727 {
3728 WARN(("invalid VidPnSourceId (%d), for displays(%d)", pSetVidPnSourceVisibility->VidPnSourceId, VBoxCommonFromDeviceExt(pDevExt)->cDisplays));
3729 return STATUS_INVALID_PARAMETER;
3730 }
3731
3732#ifdef VBOX_WITH_MESA3D
3733 if (pDevExt->enmHwType != VBOXVIDEO_HWTYPE_VMSVGA)
3734#endif
3735 vboxWddmDisplaySettingsCheckPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId);
3736
3737 NTSTATUS Status = STATUS_SUCCESS;
3738 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceVisibility->VidPnSourceId];
3739 PVBOXWDDM_ALLOCATION pAllocation = pSource->pPrimaryAllocation;
3740 if (pAllocation)
3741 {
3742 Assert(pAllocation->bVisible == pSource->bVisible);
3743 pAllocation->bVisible = pSetVidPnSourceVisibility->Visible;
3744 }
3745
3746 if (pSource->bVisible != pSetVidPnSourceVisibility->Visible)
3747 {
3748 pSource->bVisible = pSetVidPnSourceVisibility->Visible;
3749// pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_VISIBILITY;
3750// if (pDevExt->fCmdVbvaEnabled || pSource->bVisible)
3751// {
3752// vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
3753// }
3754 }
3755
3756#ifdef VBOX_WITH_MESA3D
3757 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3758 {
3759 GaVidPnSourceCheckPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId);
3760 }
3761#endif
3762
3763 LOGF(("LEAVE, status(0x%x), context(0x%x)", Status, hAdapter));
3764
3765 return Status;
3766}
3767
3768NTSTATUS
3769APIENTRY
3770DxgkDdiCommitVidPn(
3771 CONST HANDLE hAdapter,
3772 CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPnArg
3773 )
3774{
3775 LOG(("ENTER AffectedVidPnSourceId(%d) hAdapter(0x%x)", pCommitVidPnArg->AffectedVidPnSourceId, hAdapter));
3776
3777 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3778 NTSTATUS Status;
3779
3780 vboxVDbgBreakFv();
3781
3782 VBOXWDDM_SOURCE *paSources = (VBOXWDDM_SOURCE*)RTMemAlloc(sizeof (VBOXWDDM_SOURCE) * VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3783 if (!paSources)
3784 {
3785 WARN(("RTMemAlloc failed"));
3786 return STATUS_NO_MEMORY;
3787 }
3788
3789 VBOXWDDM_TARGET *paTargets = (VBOXWDDM_TARGET*)RTMemAlloc(sizeof (VBOXWDDM_TARGET) * VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3790 if (!paTargets)
3791 {
3792 WARN(("RTMemAlloc failed"));
3793 RTMemFree(paSources);
3794 return STATUS_NO_MEMORY;
3795 }
3796
3797 VBoxVidPnSourcesInit(paSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, VBOXWDDM_HGSYNC_F_SYNCED_ALL);
3798
3799 VBoxVidPnTargetsInit(paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays, VBOXWDDM_HGSYNC_F_SYNCED_ALL);
3800
3801 VBoxVidPnSourcesCopy(paSources, pDevExt->aSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3802 VBoxVidPnTargetsCopy(paTargets, pDevExt->aTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3803
3804 do {
3805 const DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
3806 Status = pDevExt->u.primary.DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPnArg->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
3807 if (!NT_SUCCESS(Status))
3808 {
3809 WARN(("DxgkCbQueryVidPnInterface failed Status 0x%x", Status));
3810 break;
3811 }
3812
3813#ifdef VBOXWDDM_DEBUG_VIDPN
3814 vboxVidPnDumpVidPn("\n>>>>COMMIT VidPN: >>>>", pDevExt, pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface, "<<<<<<<<<<<<<<<<<<<<\n");
3815#endif
3816
3817 if (pCommitVidPnArg->AffectedVidPnSourceId != D3DDDI_ID_ALL)
3818 {
3819 Status = VBoxVidPnCommitSourceModeForSrcId(
3820 pDevExt,
3821 pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface,
3822 (PVBOXWDDM_ALLOCATION)pCommitVidPnArg->hPrimaryAllocation,
3823 pCommitVidPnArg->AffectedVidPnSourceId, paSources, paTargets, pCommitVidPnArg->Flags.PathPowerTransition);
3824 if (!NT_SUCCESS(Status))
3825 {
3826 WARN(("VBoxVidPnCommitSourceModeForSrcId for current VidPn failed Status 0x%x", Status));
3827 break;
3828 }
3829 }
3830 else
3831 {
3832 Status = VBoxVidPnCommitAll(pDevExt, pCommitVidPnArg->hFunctionalVidPn, pVidPnInterface,
3833 (PVBOXWDDM_ALLOCATION)pCommitVidPnArg->hPrimaryAllocation,
3834 paSources, paTargets);
3835 if (!NT_SUCCESS(Status))
3836 {
3837 WARN(("VBoxVidPnCommitAll for current VidPn failed Status 0x%x", Status));
3838 break;
3839 }
3840 }
3841
3842 Assert(NT_SUCCESS(Status));
3843 pDevExt->u.primary.hCommittedVidPn = pCommitVidPnArg->hFunctionalVidPn;
3844 VBoxVidPnSourcesCopy(pDevExt->aSources, paSources, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3845 VBoxVidPnTargetsCopy(pDevExt->aTargets, paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3846
3847 VBoxDumpSourceTargetArrays(paSources, paTargets, VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
3848
3849#ifdef VBOX_WITH_MESA3D
3850 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
3851 {
3852 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3853 {
3854 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[i];
3855
3856 LOG(("Source [%d]: visible %d, blanked %d", i, pSource->bVisible, pSource->bBlankedByPowerOff));
3857
3858 /* Update positions of all screens. */
3859 vboxWddmDisplaySettingsQueryPos(pDevExt, i, &pSource->VScreenPos);
3860
3861 GaVidPnSourceReport(pDevExt, pSource);
3862 }
3863
3864 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
3865 {
3866 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i];
3867 Assert(pTarget->u32Id == (unsigned)i);
3868 if (pTarget->VidPnSourceId != D3DDDI_ID_UNINITIALIZED)
3869 {
3870 continue;
3871 }
3872
3873 LOG(("Target [%d]: blanked %d", i, pTarget->fBlankedByPowerOff));
3874
3875 if (pTarget->fBlankedByPowerOff)
3876 {
3877 GaScreenDefine(pDevExt->pGa, 0, pTarget->u32Id, 0, 0, 0, 0, true);
3878 }
3879 else
3880 {
3881 GaScreenDestroy(pDevExt->pGa, pTarget->u32Id);
3882 }
3883 }
3884
3885 break;
3886 }
3887#endif
3888 vboxWddmGhDisplayCheckSetInfo(pDevExt);
3889 } while (0);
3890
3891 RTMemFree(paSources);
3892 RTMemFree(paTargets);
3893
3894 LOG(("LEAVE, status(0x%x), hAdapter(0x%x)", Status, hAdapter));
3895
3896 return Status;
3897}
3898
3899NTSTATUS
3900APIENTRY
3901DxgkDdiUpdateActiveVidPnPresentPath(
3902 CONST HANDLE hAdapter,
3903 CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPathArg
3904 )
3905{
3906 RT_NOREF(hAdapter, pUpdateActiveVidPnPresentPathArg);
3907 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3908
3909 AssertBreakpoint();
3910
3911 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3912
3913 return STATUS_SUCCESS;
3914}
3915
3916NTSTATUS
3917APIENTRY
3918DxgkDdiRecommendMonitorModes(
3919 CONST HANDLE hAdapter,
3920 CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModesArg
3921 )
3922{
3923 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3924
3925 vboxVDbgBreakFv();
3926
3927 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3928
3929 NTSTATUS Status = VBoxVidPnRecommendMonitorModes(pDevExt, pRecommendMonitorModesArg->VideoPresentTargetId,
3930 pRecommendMonitorModesArg->hMonitorSourceModeSet, pRecommendMonitorModesArg->pMonitorSourceModeSetInterface);
3931 if (!NT_SUCCESS(Status))
3932 {
3933 WARN(("VBoxVidPnRecommendMonitorModes failed %#x", Status));
3934 return Status;
3935 }
3936
3937 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3938
3939 return STATUS_SUCCESS;
3940}
3941
3942NTSTATUS
3943APIENTRY
3944DxgkDdiRecommendVidPnTopology(
3945 CONST HANDLE hAdapter,
3946 CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopologyArg
3947 )
3948{
3949 RT_NOREF(hAdapter, pRecommendVidPnTopologyArg);
3950 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3951
3952 vboxVDbgBreakFv();
3953
3954 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3955
3956 return STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY;
3957}
3958
3959NTSTATUS
3960APIENTRY
3961DxgkDdiGetScanLine(
3962 CONST HANDLE hAdapter,
3963 DXGKARG_GETSCANLINE* pGetScanLine)
3964{
3965 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3966
3967 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
3968
3969#ifdef DEBUG_misha
3970// RT_BREAKPOINT();
3971#endif
3972
3973 NTSTATUS Status = VBoxWddmSlGetScanLine(pDevExt, pGetScanLine);
3974
3975 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3976
3977 return Status;
3978}
3979
3980NTSTATUS
3981APIENTRY
3982DxgkDdiStopCapture(
3983 CONST HANDLE hAdapter,
3984 CONST DXGKARG_STOPCAPTURE* pStopCapture)
3985{
3986 RT_NOREF(hAdapter, pStopCapture);
3987 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
3988
3989 AssertBreakpoint();
3990
3991 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
3992
3993 return STATUS_SUCCESS;
3994}
3995
3996NTSTATUS
3997APIENTRY
3998DxgkDdiControlInterrupt(
3999 CONST HANDLE hAdapter,
4000 CONST DXGK_INTERRUPT_TYPE InterruptType,
4001 BOOLEAN Enable
4002 )
4003{
4004 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4005
4006 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
4007 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4008
4009 switch (InterruptType)
4010 {
4011 case DXGK_INTERRUPT_DISPLAYONLY_VSYNC:
4012 case DXGK_INTERRUPT_CRTC_VSYNC:
4013 {
4014 Status = VBoxWddmSlEnableVSyncNotification(pDevExt, Enable);
4015 if (NT_SUCCESS(Status))
4016 Status = STATUS_SUCCESS; /* <- sanity */
4017 else
4018 WARN(("VSYNC Interrupt control failed Enable(%d), Status(0x%x)", Enable, Status));
4019 break;
4020 }
4021 case DXGK_INTERRUPT_DMA_COMPLETED:
4022 case DXGK_INTERRUPT_DMA_PREEMPTED:
4023 case DXGK_INTERRUPT_DMA_FAULTED:
4024 WARN(("Unexpected interrupt type! %d", InterruptType));
4025 break;
4026 default:
4027 WARN(("UNSUPPORTED interrupt type! %d", InterruptType));
4028 break;
4029 }
4030
4031 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4032
4033 return Status;
4034}
4035
4036NTSTATUS
4037APIENTRY
4038DxgkDdiCreateOverlay(
4039 CONST HANDLE hAdapter,
4040 DXGKARG_CREATEOVERLAY *pCreateOverlay)
4041{
4042 LOGF(("ENTER, hAdapter(0x%p)", hAdapter));
4043
4044 NTSTATUS Status = STATUS_SUCCESS;
4045
4046#ifdef VBOX_WITH_VIDEOHWACCEL
4047 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4048 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)vboxWddmMemAllocZero(sizeof (VBOXWDDM_OVERLAY));
4049 Assert(pOverlay);
4050 if (pOverlay)
4051 {
4052 int rc = vboxVhwaHlpOverlayCreate(pDevExt, pCreateOverlay->VidPnSourceId, &pCreateOverlay->OverlayInfo, pOverlay);
4053 AssertRC(rc);
4054 if (RT_SUCCESS(rc))
4055 {
4056 pCreateOverlay->hOverlay = pOverlay;
4057 }
4058 else
4059 {
4060 vboxWddmMemFree(pOverlay);
4061 Status = STATUS_UNSUCCESSFUL;
4062 }
4063 }
4064 else
4065 Status = STATUS_NO_MEMORY;
4066#else
4067 RT_NOREF(hAdapter, pCreateOverlay);
4068#endif
4069
4070 LOGF(("LEAVE, hAdapter(0x%p)", hAdapter));
4071
4072 return Status;
4073}
4074
4075NTSTATUS
4076APIENTRY
4077DxgkDdiDestroyDevice(
4078 CONST HANDLE hDevice)
4079{
4080 /* DxgkDdiDestroyDevice should be made pageable. */
4081 PAGED_CODE();
4082
4083 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4084
4085 vboxVDbgBreakFv();
4086
4087#ifdef VBOX_WITH_MESA3D
4088 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4089 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4090 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4091 {
4092 GaDeviceDestroy(pDevExt->pGa, pDevice);
4093 }
4094#endif
4095
4096 vboxWddmMemFree(hDevice);
4097
4098 LOGF(("LEAVE, "));
4099
4100 return STATUS_SUCCESS;
4101}
4102
4103
4104
4105/*
4106 * DxgkDdiOpenAllocation
4107 */
4108NTSTATUS
4109APIENTRY
4110DxgkDdiOpenAllocation(
4111 CONST HANDLE hDevice,
4112 CONST DXGKARG_OPENALLOCATION *pOpenAllocation)
4113{
4114 /* DxgkDdiOpenAllocation should be made pageable. */
4115 PAGED_CODE();
4116
4117 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4118
4119 vboxVDbgBreakFv();
4120
4121 NTSTATUS Status = STATUS_SUCCESS;
4122 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4123 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4124 PVBOXWDDM_RCINFO pRcInfo = NULL;
4125 if (pOpenAllocation->PrivateDriverSize)
4126 {
4127 Assert(pOpenAllocation->pPrivateDriverData);
4128 if (pOpenAllocation->PrivateDriverSize == sizeof (VBOXWDDM_RCINFO))
4129 {
4130 pRcInfo = (PVBOXWDDM_RCINFO)pOpenAllocation->pPrivateDriverData;
4131 Assert(pRcInfo->cAllocInfos == pOpenAllocation->NumAllocations);
4132 }
4133 else
4134 {
4135 WARN(("Invalid PrivateDriverSize %d", pOpenAllocation->PrivateDriverSize));
4136 Status = STATUS_INVALID_PARAMETER;
4137 }
4138 }
4139
4140 if (Status == STATUS_SUCCESS)
4141 {
4142 UINT i = 0;
4143 for (; i < pOpenAllocation->NumAllocations; ++i)
4144 {
4145 DXGK_OPENALLOCATIONINFO* pInfo = &pOpenAllocation->pOpenAllocation[i];
4146 Assert(pInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_ALLOCINFO));
4147 Assert(pInfo->pPrivateDriverData);
4148 PVBOXWDDM_ALLOCATION pAllocation = vboxWddmGetAllocationFromHandle(pDevExt, pInfo->hAllocation);
4149 if (!pAllocation)
4150 {
4151 WARN(("invalid handle"));
4152 Status = STATUS_INVALID_PARAMETER;
4153 break;
4154 }
4155
4156#ifdef DEBUG
4157 Assert(!pAllocation->fAssumedDeletion);
4158#endif
4159 if (pRcInfo)
4160 {
4161 Assert(pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC);
4162
4163 if (pInfo->PrivateDriverDataSize != sizeof (VBOXWDDM_ALLOCINFO)
4164 || !pInfo->pPrivateDriverData)
4165 {
4166 WARN(("invalid data size"));
4167 Status = STATUS_INVALID_PARAMETER;
4168 break;
4169 }
4170
4171#ifdef VBOX_WITH_VIDEOHWACCEL
4172 PVBOXWDDM_ALLOCINFO pAllocInfo = (PVBOXWDDM_ALLOCINFO)pInfo->pPrivateDriverData;
4173
4174 if (pRcInfo->RcDesc.fFlags.Overlay)
4175 {
4176 /* we have queried host for some surface info, like pitch & size,
4177 * need to return it back to the UMD (User Mode Drive) */
4178 pAllocInfo->SurfDesc = pAllocation->AllocData.SurfDesc;
4179 /* success, just continue */
4180 }
4181#endif
4182 }
4183
4184 KIRQL OldIrql;
4185 PVBOXWDDM_OPENALLOCATION pOa;
4186 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
4187 pOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
4188 if (pOa)
4189 {
4190 ++pOa->cOpens;
4191 ++pAllocation->cOpens;
4192 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4193 }
4194 else
4195 {
4196 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4197 pOa = (PVBOXWDDM_OPENALLOCATION)vboxWddmMemAllocZero(sizeof (VBOXWDDM_OPENALLOCATION));
4198 if (!pOa)
4199 {
4200 WARN(("failed to allocation alloc info"));
4201 Status = STATUS_INSUFFICIENT_RESOURCES;
4202 break;
4203 }
4204
4205 pOa->hAllocation = pInfo->hAllocation;
4206 pOa->pAllocation = pAllocation;
4207 pOa->pDevice = pDevice;
4208 pOa->cOpens = 1;
4209
4210 PVBOXWDDM_OPENALLOCATION pConcurrentOa;
4211 KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql);
4212 pConcurrentOa = VBoxWddmOaSearchLocked(pDevice, pAllocation);
4213 if (!pConcurrentOa)
4214 InsertHeadList(&pAllocation->OpenList, &pOa->ListEntry);
4215 else
4216 ++pConcurrentOa->cOpens;
4217 ++pAllocation->cOpens;
4218 KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);
4219 if (pConcurrentOa)
4220 {
4221 vboxWddmMemFree(pOa);
4222 pOa = pConcurrentOa;
4223 }
4224 }
4225
4226 pInfo->hDeviceSpecificAllocation = pOa;
4227 }
4228
4229 if (Status != STATUS_SUCCESS)
4230 {
4231 for (UINT j = 0; j < i; ++j)
4232 {
4233 DXGK_OPENALLOCATIONINFO* pInfo2Free = &pOpenAllocation->pOpenAllocation[j];
4234 PVBOXWDDM_OPENALLOCATION pOa2Free = (PVBOXWDDM_OPENALLOCATION)pInfo2Free->hDeviceSpecificAllocation;
4235 VBoxWddmOaRelease(pOa2Free);
4236 }
4237 }
4238 }
4239 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4240
4241 return Status;
4242}
4243
4244NTSTATUS
4245APIENTRY
4246DxgkDdiCloseAllocation(
4247 CONST HANDLE hDevice,
4248 CONST DXGKARG_CLOSEALLOCATION* pCloseAllocation)
4249{
4250 RT_NOREF(hDevice);
4251 /* DxgkDdiCloseAllocation should be made pageable. */
4252 PAGED_CODE();
4253
4254 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4255
4256 vboxVDbgBreakFv();
4257
4258 for (UINT i = 0; i < pCloseAllocation->NumAllocations; ++i)
4259 {
4260 PVBOXWDDM_OPENALLOCATION pOa2Free = (PVBOXWDDM_OPENALLOCATION)pCloseAllocation->pOpenHandleList[i];
4261 PVBOXWDDM_ALLOCATION pAllocation = pOa2Free->pAllocation;
4262 Assert(pAllocation->cShRcRefs >= pOa2Free->cShRcRefs);
4263 pAllocation->cShRcRefs -= pOa2Free->cShRcRefs;
4264 VBoxWddmOaRelease(pOa2Free);
4265 }
4266
4267 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4268
4269 return STATUS_SUCCESS;
4270}
4271
4272#define VBOXVDMACMD_DMA_PRESENT_BLT_MINSIZE() (VBOXVDMACMD_SIZE(VBOXVDMACMD_DMA_PRESENT_BLT))
4273#define VBOXVDMACMD_DMA_PRESENT_BLT_SIZE(_c) (VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[_c]))
4274
4275DECLINLINE(BOOLEAN) vboxWddmPixFormatConversionSupported(D3DDDIFORMAT From, D3DDDIFORMAT To)
4276{
4277 Assert(From != D3DDDIFMT_UNKNOWN);
4278 Assert(To != D3DDDIFMT_UNKNOWN);
4279 Assert(From == To);
4280 return From == To;
4281}
4282
4283NTSTATUS
4284APIENTRY
4285DxgkDdiUpdateOverlay(
4286 CONST HANDLE hOverlay,
4287 CONST DXGKARG_UPDATEOVERLAY *pUpdateOverlay)
4288{
4289 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4290
4291 NTSTATUS Status = STATUS_SUCCESS;
4292
4293#ifdef VBOX_WITH_VIDEOHWACCEL
4294 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4295 AssertPtr(pOverlay);
4296 int rc = vboxVhwaHlpOverlayUpdate(pOverlay, &pUpdateOverlay->OverlayInfo);
4297 AssertRC(rc);
4298 if (RT_FAILURE(rc))
4299 Status = STATUS_UNSUCCESSFUL;
4300#else
4301 RT_NOREF(hOverlay, pUpdateOverlay);
4302#endif
4303
4304 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4305 return Status;
4306}
4307
4308NTSTATUS
4309APIENTRY
4310DxgkDdiFlipOverlay(
4311 CONST HANDLE hOverlay,
4312 CONST DXGKARG_FLIPOVERLAY *pFlipOverlay)
4313{
4314 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4315
4316 NTSTATUS Status = STATUS_SUCCESS;
4317
4318#ifdef VBOX_WITH_VIDEOHWACCEL
4319 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4320 AssertPtr(pOverlay);
4321 int rc = vboxVhwaHlpOverlayFlip(pOverlay, pFlipOverlay);
4322 AssertRC(rc);
4323 if (RT_FAILURE(rc))
4324 Status = STATUS_UNSUCCESSFUL;
4325#else
4326 RT_NOREF(hOverlay, pFlipOverlay);
4327#endif
4328
4329 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4330
4331 return Status;
4332}
4333
4334NTSTATUS
4335APIENTRY
4336DxgkDdiDestroyOverlay(
4337 CONST HANDLE hOverlay)
4338{
4339 LOGF(("ENTER, hOverlay(0x%p)", hOverlay));
4340
4341 NTSTATUS Status = STATUS_SUCCESS;
4342
4343#ifdef VBOX_WITH_VIDEOHWACCEL
4344 PVBOXWDDM_OVERLAY pOverlay = (PVBOXWDDM_OVERLAY)hOverlay;
4345 AssertPtr(pOverlay);
4346 int rc = vboxVhwaHlpOverlayDestroy(pOverlay);
4347 AssertRC(rc);
4348 if (RT_SUCCESS(rc))
4349 vboxWddmMemFree(pOverlay);
4350 else
4351 Status = STATUS_UNSUCCESSFUL;
4352#else
4353 RT_NOREF(hOverlay);
4354#endif
4355
4356 LOGF(("LEAVE, hOverlay(0x%p)", hOverlay));
4357
4358 return Status;
4359}
4360
4361/**
4362 * DxgkDdiCreateContext
4363 */
4364NTSTATUS
4365APIENTRY
4366DxgkDdiCreateContext(
4367 CONST HANDLE hDevice,
4368 DXGKARG_CREATECONTEXT *pCreateContext)
4369{
4370 /* DxgkDdiCreateContext should be made pageable */
4371 PAGED_CODE();
4372
4373 LOGF(("ENTER, hDevice(0x%x)", hDevice));
4374
4375 vboxVDbgBreakFv();
4376
4377 if (pCreateContext->NodeOrdinal >= VBOXWDDM_NUM_NODES)
4378 {
4379 WARN(("Invalid NodeOrdinal (%d), expected to be less that (%d)\n", pCreateContext->NodeOrdinal, VBOXWDDM_NUM_NODES));
4380 return STATUS_INVALID_PARAMETER;
4381 }
4382
4383 NTSTATUS Status = STATUS_SUCCESS;
4384 PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)hDevice;
4385 PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter;
4386 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)vboxWddmMemAllocZero(sizeof (VBOXWDDM_CONTEXT));
4387 Assert(pContext);
4388 if (pContext)
4389 {
4390 pContext->pDevice = pDevice;
4391 pContext->hContext = pCreateContext->hContext;
4392 pContext->EngineAffinity = pCreateContext->EngineAffinity;
4393 pContext->NodeOrdinal = pCreateContext->NodeOrdinal;
4394 vboxVideoCmCtxInitEmpty(&pContext->CmContext);
4395 if (pCreateContext->Flags.SystemContext || pCreateContext->PrivateDriverDataSize == 0)
4396 {
4397 Assert(pCreateContext->PrivateDriverDataSize == 0);
4398 Assert(!pCreateContext->pPrivateDriverData);
4399 Assert(pCreateContext->Flags.Value <= 2); /* 2 is a GDI context in Win7 */
4400 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_SYSTEM;
4401
4402 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VBOX)
4403 {
4404 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
4405 {
4406 vboxWddmDisplaySettingsCheckPos(pDevExt, i);
4407 }
4408 }
4409 Status = STATUS_SUCCESS;
4410 }
4411 else
4412 {
4413 Assert(pCreateContext->Flags.Value == 0);
4414 Assert(pCreateContext->PrivateDriverDataSize == sizeof (VBOXWDDM_CREATECONTEXT_INFO));
4415 Assert(pCreateContext->pPrivateDriverData);
4416 if (pCreateContext->PrivateDriverDataSize == sizeof (VBOXWDDM_CREATECONTEXT_INFO))
4417 {
4418 PVBOXWDDM_CREATECONTEXT_INFO pInfo = (PVBOXWDDM_CREATECONTEXT_INFO)pCreateContext->pPrivateDriverData;
4419 switch (pInfo->enmType)
4420 {
4421 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE:
4422 {
4423 pContext->enmType = pInfo->enmType;
4424 ASMAtomicIncU32(&pDevExt->cContextsDispIfResize);
4425 break;
4426 }
4427 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS:
4428 {
4429 pContext->enmType = pInfo->enmType;
4430 Status = vboxVideoCmCtxAdd(&pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext, (HANDLE)pInfo->u.vbox.hUmEvent, pInfo->u.vbox.u64UmInfo);
4431 if (!NT_SUCCESS(Status))
4432 {
4433 WARN(("vboxVideoCmCtxAdd failed, Status 0x%x", Status));
4434 }
4435 break;
4436 }
4437#ifdef VBOX_WITH_MESA3D
4438 case VBOXWDDM_CONTEXT_TYPE_GA_3D:
4439 {
4440 pContext->enmType = VBOXWDDM_CONTEXT_TYPE_GA_3D;
4441 Status = GaContextCreate(pDevExt->pGa, pInfo, pContext);
4442 break;
4443 }
4444#endif
4445 default:
4446 {
4447 WARN(("unsupported context type %d", pInfo->enmType));
4448 Status = STATUS_INVALID_PARAMETER;
4449 break;
4450 }
4451 }
4452 }
4453 }
4454
4455 if (Status == STATUS_SUCCESS)
4456 {
4457 pCreateContext->hContext = pContext;
4458 pCreateContext->ContextInfo.DmaBufferSize = VBOXWDDM_C_DMA_BUFFER_SIZE;
4459 pCreateContext->ContextInfo.DmaBufferSegmentSet = 0;
4460 pCreateContext->ContextInfo.DmaBufferPrivateDataSize = VBOXWDDM_C_DMA_PRIVATEDATA_SIZE;
4461 pCreateContext->ContextInfo.AllocationListSize = VBOXWDDM_C_ALLOC_LIST_SIZE;
4462 pCreateContext->ContextInfo.PatchLocationListSize = VBOXWDDM_C_PATH_LOCATION_LIST_SIZE;
4463 //#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN7)
4464 //# error port to Win7 DDI
4465 // //pCreateContext->ContextInfo.DmaBufferAllocationGroup = ???;
4466 //#endif // DXGKDDI_INTERFACE_VERSION
4467 }
4468 else
4469 vboxWddmMemFree(pContext);
4470 }
4471 else
4472 Status = STATUS_NO_MEMORY;
4473
4474 LOGF(("LEAVE, hDevice(0x%x)", hDevice));
4475
4476 return Status;
4477}
4478
4479NTSTATUS
4480APIENTRY
4481DxgkDdiDestroyContext(
4482 CONST HANDLE hContext)
4483{
4484 LOGF(("ENTER, hContext(0x%x)", hContext));
4485 vboxVDbgBreakFv();
4486 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext;
4487 PVBOXMP_DEVEXT pDevExt = pContext->pDevice->pAdapter;
4488 NTSTATUS Status = STATUS_SUCCESS;
4489
4490 switch(pContext->enmType)
4491 {
4492 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE:
4493 {
4494 uint32_t cContexts = ASMAtomicDecU32(&pDevExt->cContextsDispIfResize);
4495 Assert(cContexts < UINT32_MAX/2);
4496 if (!cContexts)
4497 {
4498 if (pDevExt->fDisableTargetUpdate)
4499 {
4500 pDevExt->fDisableTargetUpdate = FALSE;
4501 vboxWddmGhDisplayCheckSetInfoEx(pDevExt, true);
4502 }
4503 }
4504 break;
4505 }
4506 case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS:
4507 {
4508 Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext);
4509 if (!NT_SUCCESS(Status))
4510 WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status));
4511
4512 Assert(pContext->CmContext.pSession == NULL);
4513 break;
4514 }
4515#ifdef VBOX_WITH_MESA3D
4516 case VBOXWDDM_CONTEXT_TYPE_GA_3D:
4517 {
4518 Status = GaContextDestroy(pDevExt->pGa, pContext);
4519 break;
4520 }
4521#endif
4522 default:
4523 break;
4524 }
4525
4526 Status = vboxVideoAMgrCtxDestroy(&pContext->AllocContext);
4527 if (NT_SUCCESS(Status))
4528 {
4529 Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->CmMgr, &pContext->CmContext);
4530 if (NT_SUCCESS(Status))
4531 vboxWddmMemFree(pContext);
4532 else
4533 WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status));
4534 }
4535 else
4536 WARN(("vboxVideoAMgrCtxDestroy failed, Status 0x%x", Status));
4537
4538 LOGF(("LEAVE, hContext(0x%x)", hContext));
4539
4540 return Status;
4541}
4542
4543NTSTATUS
4544APIENTRY
4545DxgkDdiLinkDevice(
4546 __in CONST PDEVICE_OBJECT PhysicalDeviceObject,
4547 __in CONST PVOID MiniportDeviceContext,
4548 __inout PLINKED_DEVICE LinkedDevice
4549 )
4550{
4551 RT_NOREF(PhysicalDeviceObject, MiniportDeviceContext, LinkedDevice);
4552 LOGF(("ENTER, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
4553 vboxVDbgBreakFv();
4554 AssertBreakpoint();
4555 LOGF(("LEAVE, MiniportDeviceContext(0x%x)", MiniportDeviceContext));
4556 return STATUS_NOT_IMPLEMENTED;
4557}
4558
4559NTSTATUS
4560APIENTRY
4561DxgkDdiSetDisplayPrivateDriverFormat(
4562 CONST HANDLE hAdapter,
4563 /*CONST*/ DXGKARG_SETDISPLAYPRIVATEDRIVERFORMAT* pSetDisplayPrivateDriverFormat
4564 )
4565{
4566 RT_NOREF(hAdapter, pSetDisplayPrivateDriverFormat);
4567 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4568 vboxVDbgBreakFv();
4569 AssertBreakpoint();
4570 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4571 return STATUS_SUCCESS;
4572}
4573
4574NTSTATUS APIENTRY CALLBACK DxgkDdiRestartFromTimeout(IN_CONST_HANDLE hAdapter)
4575{
4576 RT_NOREF(hAdapter);
4577 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4578 vboxVDbgBreakFv();
4579 AssertBreakpoint();
4580 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4581 return STATUS_SUCCESS;
4582}
4583
4584static NTSTATUS APIENTRY DxgkDdiQueryVidPnHWCapability(
4585 __in const HANDLE hAdapter,
4586 __inout DXGKARG_QUERYVIDPNHWCAPABILITY *pVidPnHWCaps
4587 )
4588{
4589 RT_NOREF(hAdapter);
4590 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4591 vboxVDbgBreakF();
4592 pVidPnHWCaps->VidPnHWCaps.DriverRotation = 0;
4593 pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0;
4594 pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0;
4595 pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 0;
4596 pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0;
4597 pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0;
4598 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4599 return STATUS_SUCCESS;
4600}
4601
4602static NTSTATUS APIENTRY DxgkDdiPresentDisplayOnly(
4603 _In_ const HANDLE hAdapter,
4604 _In_ const DXGKARG_PRESENT_DISPLAYONLY *pPresentDisplayOnly
4605 )
4606{
4607 LOGF(("ENTER, hAdapter(0x%x)", hAdapter));
4608 vboxVDbgBreakFv();
4609
4610 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter;
4611#ifdef VBOX_WITH_MESA3D
4612 if (pDevExt->enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4613 {
4614 return GaDxgkDdiPresentDisplayOnly(hAdapter, pPresentDisplayOnly);
4615 }
4616#endif
4617 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pPresentDisplayOnly->VidPnSourceId];
4618 Assert(pSource->AllocData.Addr.SegmentId == 1);
4619 VBOXWDDM_ALLOC_DATA SrcAllocData;
4620 SrcAllocData.SurfDesc.width = pPresentDisplayOnly->Pitch * pPresentDisplayOnly->BytesPerPixel;
4621 SrcAllocData.SurfDesc.height = ~0UL;
4622 switch (pPresentDisplayOnly->BytesPerPixel)
4623 {
4624 case 4:
4625 SrcAllocData.SurfDesc.format = D3DDDIFMT_A8R8G8B8;
4626 break;
4627 case 3:
4628 SrcAllocData.SurfDesc.format = D3DDDIFMT_R8G8B8;
4629 break;
4630 case 2:
4631 SrcAllocData.SurfDesc.format = D3DDDIFMT_R5G6B5;
4632 break;
4633 case 1:
4634 SrcAllocData.SurfDesc.format = D3DDDIFMT_P8;
4635 break;
4636 default:
4637 WARN(("Unknown format"));
4638 SrcAllocData.SurfDesc.format = D3DDDIFMT_UNKNOWN;
4639 break;
4640 }
4641 SrcAllocData.SurfDesc.bpp = pPresentDisplayOnly->BytesPerPixel >> 3;
4642 SrcAllocData.SurfDesc.pitch = pPresentDisplayOnly->Pitch;
4643 SrcAllocData.SurfDesc.depth = 1;
4644 SrcAllocData.SurfDesc.slicePitch = pPresentDisplayOnly->Pitch;
4645 SrcAllocData.SurfDesc.cbSize = ~0UL;
4646 SrcAllocData.Addr.SegmentId = 0;
4647 SrcAllocData.Addr.pvMem = pPresentDisplayOnly->pSource;
4648 SrcAllocData.hostID = 0;
4649
4650 RECT UpdateRect;
4651 RT_ZERO(UpdateRect);
4652 BOOLEAN bUpdateRectInited = FALSE;
4653
4654 for (UINT i = 0; i < pPresentDisplayOnly->NumMoves; ++i)
4655 {
4656 if (!bUpdateRectInited)
4657 {
4658 UpdateRect = pPresentDisplayOnly->pMoves[i].DestRect;
4659 bUpdateRectInited = TRUE;
4660 }
4661 else
4662 vboxWddmRectUnite(&UpdateRect, &pPresentDisplayOnly->pMoves[i].DestRect);
4663 vboxVdmaGgDmaBltPerform(pDevExt, &SrcAllocData, &pPresentDisplayOnly->pMoves[i].DestRect, &pSource->AllocData, &pPresentDisplayOnly->pMoves[i].DestRect);
4664 }
4665
4666 for (UINT i = 0; i < pPresentDisplayOnly->NumDirtyRects; ++i)
4667 {
4668 RECT *pDirtyRect = &pPresentDisplayOnly->pDirtyRect[i];
4669
4670 if (pDirtyRect->left >= pDirtyRect->right || pDirtyRect->top >= pDirtyRect->bottom)
4671 {
4672 WARN(("Wrong dirty rect (%d, %d)-(%d, %d)",
4673 pDirtyRect->left, pDirtyRect->top, pDirtyRect->right, pDirtyRect->bottom));
4674 continue;
4675 }
4676
4677 vboxVdmaGgDmaBltPerform(pDevExt, &SrcAllocData, pDirtyRect, &pSource->AllocData, pDirtyRect);
4678
4679 if (!bUpdateRectInited)
4680 {
4681 UpdateRect = *pDirtyRect;
4682 bUpdateRectInited = TRUE;
4683 }
4684 else
4685 vboxWddmRectUnite(&UpdateRect, pDirtyRect);
4686 }
4687
4688 if (bUpdateRectInited && pSource->bVisible)
4689 {
4690 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UpdateRect);
4691 }
4692
4693 LOGF(("LEAVE, hAdapter(0x%x)", hAdapter));
4694 return STATUS_SUCCESS;
4695}
4696
4697static NTSTATUS DxgkDdiStopDeviceAndReleasePostDisplayOwnership(
4698 _In_ PVOID MiniportDeviceContext,
4699 _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
4700 _Out_ PDXGK_DISPLAY_INFORMATION DisplayInfo
4701)
4702{
4703 RT_NOREF(MiniportDeviceContext, TargetId, DisplayInfo);
4704 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4705 vboxVDbgBreakFv();
4706 AssertBreakpoint();
4707 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4708 return STATUS_NOT_SUPPORTED;
4709}
4710
4711static NTSTATUS DxgkDdiSystemDisplayEnable(
4712 _In_ PVOID MiniportDeviceContext,
4713 _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
4714 _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
4715 _Out_ UINT *Width,
4716 _Out_ UINT *Height,
4717 _Out_ D3DDDIFORMAT *ColorFormat
4718 )
4719{
4720 RT_NOREF(MiniportDeviceContext, TargetId, Flags, Width, Height, ColorFormat);
4721 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4722 vboxVDbgBreakFv();
4723 AssertBreakpoint();
4724 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4725 return STATUS_NOT_SUPPORTED;
4726}
4727
4728static VOID DxgkDdiSystemDisplayWrite(
4729 _In_ PVOID MiniportDeviceContext,
4730 _In_ PVOID Source,
4731 _In_ UINT SourceWidth,
4732 _In_ UINT SourceHeight,
4733 _In_ UINT SourceStride,
4734 _In_ UINT PositionX,
4735 _In_ UINT PositionY
4736)
4737{
4738 RT_NOREF(MiniportDeviceContext, Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY);
4739 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4740 vboxVDbgBreakFv();
4741 AssertBreakpoint();
4742 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4743}
4744
4745static NTSTATUS DxgkDdiGetChildContainerId(
4746 _In_ PVOID MiniportDeviceContext,
4747 _In_ ULONG ChildUid,
4748 _Inout_ PDXGK_CHILD_CONTAINER_ID ContainerId
4749)
4750{
4751 RT_NOREF(MiniportDeviceContext, ChildUid, ContainerId);
4752 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4753 vboxVDbgBreakFv();
4754 AssertBreakpoint();
4755 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4756 return STATUS_SUCCESS;
4757}
4758
4759static NTSTATUS APIENTRY DxgkDdiSetPowerComponentFState(
4760 _In_ const HANDLE DriverContext,
4761 UINT ComponentIndex,
4762 UINT FState
4763)
4764{
4765 RT_NOREF(DriverContext, ComponentIndex, FState);
4766 LOGF(("ENTER, DriverContext(0x%x)", DriverContext));
4767 vboxVDbgBreakFv();
4768 AssertBreakpoint();
4769 LOGF(("LEAVE, DriverContext(0x%x)", DriverContext));
4770 return STATUS_SUCCESS;
4771}
4772
4773static NTSTATUS APIENTRY DxgkDdiPowerRuntimeControlRequest(
4774 _In_ const HANDLE DriverContext,
4775 _In_ LPCGUID PowerControlCode,
4776 _In_opt_ PVOID InBuffer,
4777 _In_ SIZE_T InBufferSize,
4778 _Out_opt_ PVOID OutBuffer,
4779 _In_ SIZE_T OutBufferSize,
4780 _Out_opt_ PSIZE_T BytesReturned
4781)
4782{
4783 RT_NOREF(DriverContext, PowerControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned);
4784 LOGF(("ENTER, DriverContext(0x%x)", DriverContext));
4785 vboxVDbgBreakFv();
4786 AssertBreakpoint();
4787 LOGF(("LEAVE, DriverContext(0x%x)", DriverContext));
4788 return STATUS_SUCCESS;
4789}
4790
4791static NTSTATUS DxgkDdiNotifySurpriseRemoval(
4792 _In_ PVOID MiniportDeviceContext,
4793 _In_ DXGK_SURPRISE_REMOVAL_TYPE RemovalType
4794 )
4795{
4796 RT_NOREF(MiniportDeviceContext, RemovalType);
4797 LOGF(("ENTER, hAdapter(0x%x)", MiniportDeviceContext));
4798 vboxVDbgBreakFv();
4799 AssertBreakpoint();
4800 LOGF(("LEAVE, hAdapter(0x%x)", MiniportDeviceContext));
4801 return STATUS_SUCCESS;
4802}
4803
4804static BOOLEAN DxgkDdiInterruptRoutine(const PVOID MiniportDeviceContext,
4805 ULONG MessageNumber)
4806{
4807#ifdef VBOX_WITH_MESA3D
4808 BOOLEAN const fVMSVGA = GaDxgkDdiInterruptRoutine(MiniportDeviceContext, MessageNumber);
4809#else
4810 BOOLEAN const fVMSVGA = FALSE;
4811#endif
4812
4813 BOOLEAN const fHGSMI = DxgkDdiInterruptRoutineLegacy(MiniportDeviceContext, MessageNumber);
4814 return fVMSVGA || fHGSMI;
4815}
4816
4817static VOID DxgkDdiDpcRoutine(const PVOID MiniportDeviceContext)
4818{
4819 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext;
4820
4821#ifdef VBOX_WITH_MESA3D
4822 GaDxgkDdiDpcRoutine(MiniportDeviceContext);
4823#endif
4824 DxgkDdiDpcRoutineLegacy(MiniportDeviceContext);
4825
4826 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
4827}
4828
4829static NTSTATUS vboxWddmInitDisplayOnlyDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
4830{
4831 KMDDOD_INITIALIZATION_DATA DriverInitializationData = {'\0'};
4832
4833 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_WIN8;
4834
4835 DriverInitializationData.DxgkDdiAddDevice = DxgkDdiAddDevice;
4836 DriverInitializationData.DxgkDdiStartDevice = DxgkDdiStartDevice;
4837 DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice;
4838 DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice;
4839 DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest;
4840 DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine;
4841 DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine;
4842 DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations;
4843 DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus;
4844 DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor;
4845 DriverInitializationData.DxgkDdiSetPowerState = DxgkDdiSetPowerState;
4846 DriverInitializationData.DxgkDdiNotifyAcpiEvent = DxgkDdiNotifyAcpiEvent;
4847 DriverInitializationData.DxgkDdiResetDevice = DxgkDdiResetDevice;
4848 DriverInitializationData.DxgkDdiUnload = DxgkDdiUnload;
4849 DriverInitializationData.DxgkDdiQueryInterface = DxgkDdiQueryInterface;
4850 DriverInitializationData.DxgkDdiControlEtwLogging = DxgkDdiControlEtwLogging;
4851 DriverInitializationData.DxgkDdiQueryAdapterInfo = DxgkDdiQueryAdapterInfo;
4852 DriverInitializationData.DxgkDdiSetPalette = DxgkDdiSetPalette;
4853 DriverInitializationData.DxgkDdiSetPointerPosition = DxgkDdiSetPointerPosition;
4854 DriverInitializationData.DxgkDdiSetPointerShape = DxgkDdiSetPointerShape;
4855 DriverInitializationData.DxgkDdiEscape = DxgkDdiEscape;
4856 DriverInitializationData.DxgkDdiCollectDbgInfo = DxgkDdiCollectDbgInfo;
4857 DriverInitializationData.DxgkDdiIsSupportedVidPn = DxgkDdiIsSupportedVidPn;
4858 DriverInitializationData.DxgkDdiRecommendFunctionalVidPn = DxgkDdiRecommendFunctionalVidPn;
4859 DriverInitializationData.DxgkDdiEnumVidPnCofuncModality = DxgkDdiEnumVidPnCofuncModality;
4860 DriverInitializationData.DxgkDdiSetVidPnSourceVisibility = DxgkDdiSetVidPnSourceVisibility;
4861 DriverInitializationData.DxgkDdiCommitVidPn = DxgkDdiCommitVidPn;
4862 DriverInitializationData.DxgkDdiUpdateActiveVidPnPresentPath = DxgkDdiUpdateActiveVidPnPresentPath;
4863 DriverInitializationData.DxgkDdiRecommendMonitorModes = DxgkDdiRecommendMonitorModes;
4864 DriverInitializationData.DxgkDdiQueryVidPnHWCapability = DxgkDdiQueryVidPnHWCapability;
4865 DriverInitializationData.DxgkDdiPresentDisplayOnly = DxgkDdiPresentDisplayOnly;
4866 DriverInitializationData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = DxgkDdiStopDeviceAndReleasePostDisplayOwnership;
4867 DriverInitializationData.DxgkDdiSystemDisplayEnable = DxgkDdiSystemDisplayEnable;
4868 DriverInitializationData.DxgkDdiSystemDisplayWrite = DxgkDdiSystemDisplayWrite;
4869// DriverInitializationData.DxgkDdiGetChildContainerId = DxgkDdiGetChildContainerId;
4870// DriverInitializationData.DxgkDdiSetPowerComponentFState = DxgkDdiSetPowerComponentFState;
4871// DriverInitializationData.DxgkDdiPowerRuntimeControlRequest = DxgkDdiPowerRuntimeControlRequest;
4872// DriverInitializationData.DxgkDdiNotifySurpriseRemoval = DxgkDdiNotifySurpriseRemoval;
4873
4874 /* Display-only driver is not required to report VSYNC.
4875 * The Microsoft KMDOD driver sample does not implement DxgkDdiControlInterrupt and DxgkDdiGetScanLine.
4876 * The functions must be either both implemented or none implemented.
4877 * Windows 10 10586 guests had problems with VSYNC in display-only driver (#8228).
4878 * Therefore the driver does not implement DxgkDdiControlInterrupt and DxgkDdiGetScanLine.
4879 */
4880
4881 NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject,
4882 pRegistryPath,
4883 &DriverInitializationData);
4884 if (!NT_SUCCESS(Status))
4885 {
4886 WARN(("DxgkInitializeDisplayOnlyDriver failed! Status 0x%x", Status));
4887 }
4888 return Status;
4889}
4890
4891static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath, VBOXVIDEO_HWTYPE enmHwType)
4892{
4893 DRIVER_INITIALIZATION_DATA DriverInitializationData = {'\0'};
4894
4895 // Fill in the DriverInitializationData structure and call DxgkInitialize()
4896 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
4897 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_WIN8;
4898 else
4899 DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION_VISTA_SP1;
4900
4901 DriverInitializationData.DxgkDdiAddDevice = DxgkDdiAddDevice;
4902 DriverInitializationData.DxgkDdiStartDevice = DxgkDdiStartDevice;
4903 DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice;
4904 DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice;
4905 DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest;
4906 DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine;
4907 DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine;
4908
4909#ifdef VBOX_WITH_MESA3D
4910 if (enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
4911 {
4912 DriverInitializationData.DxgkDdiPatch = GaDxgkDdiPatch;
4913 DriverInitializationData.DxgkDdiSubmitCommand = GaDxgkDdiSubmitCommand;
4914 DriverInitializationData.DxgkDdiPreemptCommand = GaDxgkDdiPreemptCommand;
4915 DriverInitializationData.DxgkDdiBuildPagingBuffer = GaDxgkDdiBuildPagingBuffer;
4916 DriverInitializationData.DxgkDdiQueryCurrentFence = GaDxgkDdiQueryCurrentFence;
4917 DriverInitializationData.DxgkDdiRender = GaDxgkDdiRender;
4918 DriverInitializationData.DxgkDdiPresent = GaDxgkDdiPresent;
4919 }
4920 else
4921#endif
4922 {
4923 RT_NOREF(enmHwType);
4924
4925 DriverInitializationData.DxgkDdiPatch = DxgkDdiPatchLegacy;
4926 DriverInitializationData.DxgkDdiSubmitCommand = DxgkDdiSubmitCommandLegacy;
4927 DriverInitializationData.DxgkDdiPreemptCommand = DxgkDdiPreemptCommandLegacy;
4928 DriverInitializationData.DxgkDdiBuildPagingBuffer = DxgkDdiBuildPagingBufferLegacy;
4929 DriverInitializationData.DxgkDdiQueryCurrentFence = DxgkDdiQueryCurrentFenceLegacy;
4930 DriverInitializationData.DxgkDdiRender = DxgkDdiRenderLegacy;
4931 DriverInitializationData.DxgkDdiPresent = DxgkDdiPresentLegacy;
4932 }
4933
4934 DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations;
4935 DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus;
4936 DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor;
4937 DriverInitializationData.DxgkDdiSetPowerState = DxgkDdiSetPowerState;
4938 DriverInitializationData.DxgkDdiNotifyAcpiEvent = DxgkDdiNotifyAcpiEvent;
4939 DriverInitializationData.DxgkDdiResetDevice = DxgkDdiResetDevice;
4940 DriverInitializationData.DxgkDdiUnload = DxgkDdiUnload;
4941 DriverInitializationData.DxgkDdiQueryInterface = DxgkDdiQueryInterface;
4942 DriverInitializationData.DxgkDdiControlEtwLogging = DxgkDdiControlEtwLogging;
4943
4944 DriverInitializationData.DxgkDdiQueryAdapterInfo = DxgkDdiQueryAdapterInfo;
4945 DriverInitializationData.DxgkDdiCreateDevice = DxgkDdiCreateDevice;
4946 DriverInitializationData.DxgkDdiCreateAllocation = DxgkDdiCreateAllocation;
4947 DriverInitializationData.DxgkDdiDestroyAllocation = DxgkDdiDestroyAllocation;
4948 DriverInitializationData.DxgkDdiDescribeAllocation = DxgkDdiDescribeAllocation;
4949 DriverInitializationData.DxgkDdiGetStandardAllocationDriverData = DxgkDdiGetStandardAllocationDriverData;
4950 DriverInitializationData.DxgkDdiAcquireSwizzlingRange = DxgkDdiAcquireSwizzlingRange;
4951 DriverInitializationData.DxgkDdiReleaseSwizzlingRange = DxgkDdiReleaseSwizzlingRange;
4952
4953 DriverInitializationData.DxgkDdiSetPalette = DxgkDdiSetPalette;
4954 DriverInitializationData.DxgkDdiSetPointerPosition = DxgkDdiSetPointerPosition;
4955 DriverInitializationData.DxgkDdiSetPointerShape = DxgkDdiSetPointerShape;
4956 DriverInitializationData.DxgkDdiResetFromTimeout = DxgkDdiResetFromTimeout;
4957 DriverInitializationData.DxgkDdiRestartFromTimeout = DxgkDdiRestartFromTimeout;
4958 DriverInitializationData.DxgkDdiEscape = DxgkDdiEscape;
4959 DriverInitializationData.DxgkDdiCollectDbgInfo = DxgkDdiCollectDbgInfo;
4960 DriverInitializationData.DxgkDdiIsSupportedVidPn = DxgkDdiIsSupportedVidPn;
4961 DriverInitializationData.DxgkDdiRecommendFunctionalVidPn = DxgkDdiRecommendFunctionalVidPn;
4962 DriverInitializationData.DxgkDdiEnumVidPnCofuncModality = DxgkDdiEnumVidPnCofuncModality;
4963 DriverInitializationData.DxgkDdiSetVidPnSourceAddress = DxgkDdiSetVidPnSourceAddress;
4964 DriverInitializationData.DxgkDdiSetVidPnSourceVisibility = DxgkDdiSetVidPnSourceVisibility;
4965 DriverInitializationData.DxgkDdiCommitVidPn = DxgkDdiCommitVidPn;
4966 DriverInitializationData.DxgkDdiUpdateActiveVidPnPresentPath = DxgkDdiUpdateActiveVidPnPresentPath;
4967 DriverInitializationData.DxgkDdiRecommendMonitorModes = DxgkDdiRecommendMonitorModes;
4968 DriverInitializationData.DxgkDdiRecommendVidPnTopology = DxgkDdiRecommendVidPnTopology;
4969 DriverInitializationData.DxgkDdiGetScanLine = DxgkDdiGetScanLine;
4970 DriverInitializationData.DxgkDdiStopCapture = DxgkDdiStopCapture;
4971 DriverInitializationData.DxgkDdiControlInterrupt = DxgkDdiControlInterrupt;
4972 DriverInitializationData.DxgkDdiCreateOverlay = DxgkDdiCreateOverlay;
4973
4974 DriverInitializationData.DxgkDdiDestroyDevice = DxgkDdiDestroyDevice;
4975 DriverInitializationData.DxgkDdiOpenAllocation = DxgkDdiOpenAllocation;
4976 DriverInitializationData.DxgkDdiCloseAllocation = DxgkDdiCloseAllocation;
4977
4978 DriverInitializationData.DxgkDdiUpdateOverlay = DxgkDdiUpdateOverlay;
4979 DriverInitializationData.DxgkDdiFlipOverlay = DxgkDdiFlipOverlay;
4980 DriverInitializationData.DxgkDdiDestroyOverlay = DxgkDdiDestroyOverlay;
4981
4982 DriverInitializationData.DxgkDdiCreateContext = DxgkDdiCreateContext;
4983 DriverInitializationData.DxgkDdiDestroyContext = DxgkDdiDestroyContext;
4984
4985 DriverInitializationData.DxgkDdiLinkDevice = NULL; //DxgkDdiLinkDevice;
4986 DriverInitializationData.DxgkDdiSetDisplayPrivateDriverFormat = DxgkDdiSetDisplayPrivateDriverFormat;
4987
4988 if (DriverInitializationData.Version >= DXGKDDI_INTERFACE_VERSION_WIN7)
4989 {
4990 DriverInitializationData.DxgkDdiQueryVidPnHWCapability = DxgkDdiQueryVidPnHWCapability;
4991 }
4992
4993 NTSTATUS Status = DxgkInitialize(pDriverObject,
4994 pRegistryPath,
4995 &DriverInitializationData);
4996 if (!NT_SUCCESS(Status))
4997 {
4998 WARN(("DxgkInitialize failed! Status 0x%x", Status));
4999 }
5000 return Status;
5001}
5002
5003NTSTATUS
5004DriverEntry(
5005 IN PDRIVER_OBJECT DriverObject,
5006 IN PUNICODE_STRING RegistryPath
5007 )
5008{
5009 PAGED_CODE();
5010
5011 vboxVDbgBreakFv();
5012
5013 int irc = RTR0Init(0);
5014 if (RT_FAILURE(irc))
5015 {
5016 RTLogBackdoorPrintf("VBoxWddm: RTR0Init failed: %Rrc!\n", irc);
5017 return STATUS_UNSUCCESSFUL;
5018 }
5019
5020#if 0//def DEBUG_misha
5021 RTLogGroupSettings(0, "+default.e.l.f.l2.l3");
5022#endif
5023
5024#ifdef DEBUG
5025#define VBOXWDDM_BUILD_TYPE "dbg"
5026#else
5027#define VBOXWDDM_BUILD_TYPE "rel"
5028#endif
5029
5030 LOGREL(("VBox WDDM Driver for Windows %s version %d.%d.%dr%d %s, %d bit; Built %s %s",
5031 VBoxQueryWinVersion(NULL) >= WINVERSION_8 ? "8+" : "Vista and 7",
5032 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
5033 VBOXWDDM_BUILD_TYPE,
5034 (sizeof (void*) << 3), __DATE__, __TIME__));
5035
5036 if ( !ARGUMENT_PRESENT(DriverObject)
5037 || !ARGUMENT_PRESENT(RegistryPath))
5038 return STATUS_INVALID_PARAMETER;
5039
5040 vboxWddmDrvCfgInit(RegistryPath);
5041
5042 ULONG major, minor, build;
5043 BOOLEAN fCheckedBuild = PsGetVersion(&major, &minor, &build, NULL); NOREF(fCheckedBuild);
5044 BOOLEAN f3DRequired = FALSE;
5045
5046 LOGREL(("OsVersion(%d, %d, %d)", major, minor, build));
5047
5048 NTSTATUS Status = STATUS_SUCCESS;
5049 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
5050 int rc = VbglR0InitClient();
5051 if (RT_SUCCESS(rc))
5052 {
5053 /* Check whether 3D is required by the guest. */
5054 if (major > 6)
5055 {
5056 /* Windows 10 and newer. */
5057 f3DRequired = TRUE;
5058 }
5059 else if (major == 6)
5060 {
5061 if (minor >= 2)
5062 {
5063 /* Windows 8, 8.1 and 10 preview. */
5064 f3DRequired = TRUE;
5065 }
5066 else
5067 {
5068 f3DRequired = FALSE;
5069 }
5070 }
5071 else
5072 {
5073 WARN(("Unsupported OLDER win version, ignore and assume 3D is NOT required"));
5074 f3DRequired = FALSE;
5075 }
5076
5077 LOG(("3D is %srequired!", f3DRequired? "": "NOT "));
5078
5079 /* Check whether 3D is provided by the host. */
5080 VBOXVIDEO_HWTYPE enmHwType = VBOXVIDEO_HWTYPE_VBOX;
5081 BOOL f3DSupported = FALSE;
5082
5083 if (VBoxVGACfgAvailable())
5084 {
5085 /* New configuration query interface is available. */
5086 uint32_t u32;
5087 if (VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VERSION, &u32, 0))
5088 {
5089 LOGREL(("WDDM: VGA configuration version %d", u32));
5090 }
5091
5092 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_3D, &u32, 0);
5093 f3DSupported = RT_BOOL(u32);
5094
5095 VBoxVGACfgQuery(VBE_DISPI_CFG_ID_VMSVGA, &u32, 0);
5096 if (u32)
5097 {
5098 enmHwType = VBOXVIDEO_HWTYPE_VMSVGA;
5099 }
5100 LOGREL(("WDDM: VGA configuration: 3D %d, hardware type %d", f3DSupported, enmHwType));
5101 }
5102
5103 if (enmHwType == VBOXVIDEO_HWTYPE_VBOX)
5104 {
5105 /* No 3D for legacy adapter. */
5106 f3DSupported = FALSE;
5107 }
5108 else if (enmHwType == VBOXVIDEO_HWTYPE_VMSVGA)
5109 {
5110 /* Nothing. */
5111 }
5112 else
5113 {
5114 /* No supported hardware, fallback to VBox 2D only. */
5115 enmHwType = VBOXVIDEO_HWTYPE_VBOX;
5116 f3DSupported = FALSE;
5117 }
5118
5119 LOGREL(("WDDM: 3D is %ssupported, hardware type %d", f3DSupported? "": "not ", enmHwType));
5120
5121 if (NT_SUCCESS(Status))
5122 {
5123 if (!f3DSupported)
5124 {
5125 /* No 3D support by the host. */
5126 if (VBoxQueryWinVersion(NULL) >= WINVERSION_8)
5127 {
5128 /* Use display only driver for Win8+. */
5129 g_VBoxDisplayOnly = 1;
5130
5131 /* Black list some builds. */
5132 if (major == 6 && minor == 4 && build == 9841)
5133 {
5134 /* W10 Technical preview crashes with display-only driver. */
5135 LOGREL(("3D is NOT supported by the host, fallback to the system video driver."));
5136 Status = STATUS_UNSUCCESSFUL;
5137 }
5138 else
5139 {
5140 LOGREL(("3D is NOT supported by the host, falling back to display-only mode.."));
5141 }
5142 }
5143 else
5144 {
5145 if (f3DRequired)
5146 {
5147 LOGREL(("3D is NOT supported by the host, but is required for the current guest version using this driver.."));
5148 Status = STATUS_UNSUCCESSFUL;
5149 }
5150 else
5151 LOGREL(("3D is NOT supported by the host, but is NOT required for the current guest version using this driver, continuing with Disabled 3D.."));
5152 }
5153 }
5154 }
5155
5156 if (NT_SUCCESS(Status))
5157 {
5158 if (g_VBoxDisplayOnly)
5159 {
5160 Status = vboxWddmInitDisplayOnlyDriver(DriverObject, RegistryPath);
5161 }
5162 else
5163 {
5164 Status = vboxWddmInitFullGraphicsDriver(DriverObject, RegistryPath, enmHwType);
5165 }
5166
5167 if (NT_SUCCESS(Status))
5168 {
5169 /*
5170 * Successfully initialized the driver.
5171 */
5172 return Status;
5173 }
5174
5175 /*
5176 * Cleanup on failure.
5177 */
5178 }
5179 else
5180 LOGREL(("Aborting the video driver load due to 3D support missing"));
5181
5182 VbglR0TerminateClient();
5183 }
5184 else
5185 {
5186 WARN(("VbglR0InitClient failed, rc(%d)", rc));
5187 Status = STATUS_UNSUCCESSFUL;
5188 }
5189
5190 AssertRelease(!NT_SUCCESS(Status));
5191
5192 PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
5193 if (pLogger)
5194 {
5195 RTLogDestroy(pLogger);
5196 }
5197 pLogger = RTLogSetDefaultInstance(NULL);
5198 if (pLogger)
5199 {
5200 RTLogDestroy(pLogger);
5201 }
5202
5203 return Status;
5204}
Note: See TracBrowser for help on using the repository browser.

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